From 9eedfb78267b76d73081eea6884bac912a4bf108 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Mon, 11 Jul 2022 19:19:42 +0200 Subject: [PATCH 01/18] WIP: Added init-only properties error + added some tests --- eng/Versions.props | 17 +- src/Compiler/Checking/CheckExpressions.fs | 4 + src/Compiler/Checking/infos.fs | 15 ++ src/Compiler/Checking/infos.fsi | 3 + src/Compiler/FSComp.txt | 1 + src/Compiler/xlf/FSComp.txt.cs.xlf | 5 + src/Compiler/xlf/FSComp.txt.de.xlf | 5 + src/Compiler/xlf/FSComp.txt.es.xlf | 5 + src/Compiler/xlf/FSComp.txt.fr.xlf | 5 + src/Compiler/xlf/FSComp.txt.it.xlf | 5 + src/Compiler/xlf/FSComp.txt.ja.xlf | 5 + src/Compiler/xlf/FSComp.txt.ko.xlf | 5 + src/Compiler/xlf/FSComp.txt.pl.xlf | 5 + src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 5 + src/Compiler/xlf/FSComp.txt.ru.xlf | 5 + src/Compiler/xlf/FSComp.txt.tr.xlf | 5 + src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 5 + src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 5 + .../FSharp.Compiler.ComponentTests.fsproj | 16 +- .../Interop/RequiredAndInitOnlyProperties.fs | 159 ++++++++++++++++++ .../PropertyPages/ApplicationPropPageBase.vb | 3 +- .../PropertyPages/DebugPropPage.vb | 2 +- 22 files changed, 267 insertions(+), 18 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs diff --git a/eng/Versions.props b/eng/Versions.props index 6571c5fb21a..fdee09c7fd3 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -113,8 +113,8 @@ 6.0.0 4.5.0 - 17.2.178-preview - 17.2.0-preview-1-32131-009 + 17.3.133-preview + 17.3.0-preview-1-32407-044 17.0.77-pre-g62a6cb5699 $(VisualStudioContractPackagesVersion) $(VisualStudioContractPackagesVersion) @@ -135,7 +135,7 @@ $(VisualStudioContractPackagesVersion) $(VisualStudioContractPackagesVersion) - 4.2.0-3.22154.1 + 4.4.0-1.22360.2 $(RoslynVersion) $(RoslynVersion) $(RoslynVersion) @@ -144,8 +144,9 @@ $(RoslynVersion) 2.0.28 $(RoslynVersion) + - 17.0.0 + 17.1.0 $(MicrosoftBuildOverallPackagesVersion) $(MicrosoftBuildOverallPackagesVersion) $(MicrosoftBuildOverallPackagesVersion) @@ -169,7 +170,7 @@ $(VisualStudioContractPackagesVersion) $(VisualStudioContractPackagesVersion) - 17.2.22-alpha + 17.3.3-alpha $(VisualStudioImplementationPackagesVersion) 17.0.0 $(VisualStudioContractPackagesVersion) @@ -185,9 +186,9 @@ 15.0.25123-Dev15Preview 16.0.1 16.0.28924.11111 - 17.2.10-alpha + 17.3.1-alpha $(VisualStudioContractPackagesVersion) - 17.0.46 + 17.0.53 9.0.30729 6.0.0 12.0.4 @@ -216,7 +217,7 @@ 3.11.0 2.1.80 1.0.0-beta2-dev3 - 2.11.34 + 2.12.7-alpha 2.8.57 2.4.1 2.4.2 diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 0de950283e7..77736403c76 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -9010,6 +9010,10 @@ and TcLookupThen cenv overallTy env tpenv mObjExpr objExpr objExprTy longId dela if isNil meths then error (Error (FSComp.SR.tcPropertyIsNotReadable nm, mItem)) TcMethodApplicationThen cenv env overallTy None tpenv tyArgsOpt objArgs mExprAndItem mItem nm ad PossiblyMutates true meths afterResolution NormalValUse args atomicFlag delayed else + + if pinfo.IsSetterInitOnly then + errorR (Error (FSComp.SR.tcInitOnlyPropertyCannotBeSet1 nm, mItem)) + let args = if pinfo.IsIndexer then args else [] let mut = (if isStructTy g (tyOfExpr g objExpr) then DefinitelyMutates else PossiblyMutates) TcMethodApplicationThen cenv env overallTy None tpenv tyArgsOpt objArgs mStmt mItem nm ad mut true meths afterResolution NormalValUse (args @ [expr2]) atomicFlag [] diff --git a/src/Compiler/Checking/infos.fs b/src/Compiler/Checking/infos.fs index 28c4382f918..4e71ee9ea01 100644 --- a/src/Compiler/Checking/infos.fs +++ b/src/Compiler/Checking/infos.fs @@ -1562,6 +1562,13 @@ type ILPropInfo = /// Indicates if the IL property has a 'set' method member x.HasSetter = Option.isSome x.RawMetadata.SetMethod + /// Indidcates whether IL property has an init-only setter (i.e. has the `System.Runtime.CompilerServices.IsExternalInit` modifer) + member x.IsSetterInitOnly = + match x.SetterMethod.ILMethodRef.ReturnType with + | ILType.Modified(_, cls, _) -> cls.FullName = "System.Runtime.CompilerServices.IsExternalInit" + | _ -> false + /// tcref.CompiledRepresentationForNamedType.BasicQualifiedName = "System.ReadOnlySpan`1" + /// Indicates if the IL property is static member x.IsStatic = (x.RawMetadata.CallingConv = ILThisConvention.Static) @@ -1688,6 +1695,14 @@ type PropInfo = | ProvidedProp(_, pi, m) -> pi.PUntaint((fun pi -> pi.CanWrite), m) #endif + member x.IsSetterInitOnly = + match x with + | ILProp ilpinfo -> ilpinfo.IsSetterInitOnly + | FSProp _ -> false +#if !NO_TYPEPROVIDERS + | ProvidedProp _ -> false +#endif + /// Indicates if this is an extension member member x.IsExtensionMember = match x.ArbitraryValRef with diff --git a/src/Compiler/Checking/infos.fsi b/src/Compiler/Checking/infos.fsi index dba5200afb7..97dc3d74c04 100644 --- a/src/Compiler/Checking/infos.fsi +++ b/src/Compiler/Checking/infos.fsi @@ -787,6 +787,9 @@ type PropInfo = /// Indicates if this property has an associated setter method. member HasSetter: bool + /// Indidcates whether IL property has an init-only setter (i.e. has the `System.Runtime.CompilerServices.IsExternalInit` modifer) + member IsSetterInitOnly: bool + member ImplementedSlotSignatures: SlotSig list /// Indicates if this property is marked 'override' and thus definitely overrides another property. diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index a6ce206cc8f..4438faffcd4 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -652,6 +652,7 @@ tcExpressionWithIfRequiresParenthesis,"This list or array expression includes an 808,tcLookupMayNotBeUsedHere,"This lookup cannot be used here" 809,tcPropertyIsStatic,"Property '%s' is static" 810,tcPropertyCannotBeSet1,"Property '%s' cannot be set" +810,tcInitOnlyPropertyCannotBeSet1,"Init-only property '%s' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization" 811,tcConstructorsCannotBeFirstClassValues,"Constructors must be applied to arguments and cannot be used as first-class values. If necessary use an anonymous function '(fun arg1 ... argN -> new Type(arg1,...,argN))'." 812,tcSyntaxFormUsedOnlyWithRecordLabelsPropertiesAndFields,"The syntax 'expr.id' may only be used with record labels, properties and fields" 813,tcEventIsStatic,"Event '%s' is static" diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 2982b373922..0f49940c1ec 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -697,6 +697,11 @@ Tento výraz používá implicitní převod {0} pro převod typu {1} na typ {2}. Přečtěte si téma https://aka.ms/fsharp-implicit-convs. Toto upozornění může být vypnuté pomocí '#nowarn \"3391\". + + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. Atribut InlineIfLambda je možné použít pouze u parametrů vložených funkcí metod s typem funkce nebo typem delegáta F#. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index cd9d6d81bb8..9632581132e 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -697,6 +697,11 @@ Dieser Ausdruck verwendet die implizite Konvertierung "{0}", um den Typ "{1}" in den Typ "{2}" zu konvertieren. Siehe https://aka.ms/fsharp-implicit-convs. Diese Warnung kann durch "#nowarn \" 3391 \ " deaktiviert werden. + + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. Das "InlineIfLambda-Attribut" darf nur für Parameter von Inlinefunktionen von Methoden verwendet werden, deren Typ ein Funktions-oder F #-Delegattyp ist. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index f833bc6e76c..40c60110a03 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -697,6 +697,11 @@ Esta expresión usa la conversión implícita '{0}' para convertir el tipo '{1}' al tipo '{2}'. Consulte https://aka.ms/fsharp-implicit-convs. Esta advertencia se puede deshabilitar mediante '#nowarn \"3391\". + + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. El atributo "InlineIfLambda" solo se puede usar en los parámetros de funciones insertadas de métodos cuyo tipo es una función o un tipo de delegado F#. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index c949833a13a..c81fcbd170d 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -697,6 +697,11 @@ Cette expression utilise la conversion implicite « {0}<» pour convertir le type « {1} » en type « {2} ». Voir https://aka.ms/fsharp-implicit-convs. Cet avertissement peut être désactivé à l’aide de '#nowarn \"3391\". + + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. L’attribut « InlineIfLambda » ne peut être utilisé que sur les paramètres des fonctions incorporées des méthodes dont le type est une fonction ou un type délégué F#. diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index a9b2e133bde..40b8c2baa9b 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -697,6 +697,11 @@ Questa espressione usa la conversione implicita '{0}' per convertire il tipo '{1}' nel tipo '{2}'. Vedere https://aka.ms/fsharp-implicit-convs. Per disabilitare questo avviso, usare '#nowarn \"3391\"'. + + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. L'attributo 'InlineIfLambda' può essere usato solo in parametri di funzioni impostate come inline di metodi il cui tipo è un tipo di funzione o delegato F#. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index d0637747c7a..2d3eb504a83 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -697,6 +697,11 @@ この式では、暗黙的な変換 '{0}' を使用して、型 '{1}' を型 '{2}' に変換しています。https://aka.ms/fsharp-implicit-convs をご確認ください。'#nowarn\"3391\" を使用して、この警告を無効にできる可能性があります。 + + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. 'InlineIfLambda' 属性を使用できるのは、型が関数または F# デリゲート型であるメソッドのインライン関数のパラメーターに対してのみです。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index fbbfdfbf306..b5933e98fdc 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -697,6 +697,11 @@ 이 식은 암시적 변환 '{0}'을 사용하여 '{1}' 형식을 '{2}' 형식으로 변환 합니다. https://aka.ms/fsharp-implicit-convs 참조. ’#Nowarn \ "3391\"을 (를) 사용하여 이 경고를 사용 하지 않도록 설정할 수 있습니다. + + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. 'InlineIfLambda' 특성은 형식이 함수 또는 F# 대리자 형식인 메서드의 인라인 함수 매개 변수에만 사용할 수 있습니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index fbfb4f7e730..17cca816ffd 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -697,6 +697,11 @@ W tym wyrażeniu jest używana bezwzględna konwersja "{0}" w celu przekonwertowania typu "{1}" na typ "{2}". Zobacz https://aka.ms/fsharp-implicit-convs. To ostrzeżenie można wyłączyć przy użyciu polecenia "#nowarn \" 3391 \ ". + + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. Atrybut "InlineIfLambda" może być używany tylko w przypadku parametrów funkcji z podkreśleniem metod, których typ to funkcja lub typ delegata języka F #. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 83b76374d27..d1eb2b66c4a 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -697,6 +697,11 @@ Essa expressão usa a conversão implícita '{0}' para converter o tipo '{1}' ao tipo '{2}'. Consulte https://aka.ms/fsharp-implicit-convs. Este aviso pode ser desabilitado usando '#nowarn\"3391\". + + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. O atributo 'InlineIfLambda' só pode ser usado em parâmetros de funções de métodos em linha cujo tipo seja uma função ou F# tipo delegado. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 93db1f6740a..4975d0dbdd0 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -697,6 +697,11 @@ Это выражение использует неявное преобразование "{0}" для преобразования типа "{1}" в тип "{2}". См. сведения на странице https://aka.ms/fsharp-implicit-convs. Это предупреждение можно отключить, используя параметр '#nowarn \"3391\" + + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. Атрибут "InlineIfLambda" может использоваться только в параметрах встраиваемых функций методов, типом которых является функция или делегат F#. diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index acff017e25a..08722dc26f1 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -697,6 +697,11 @@ Bu ifade '{1}' türünü '{2}' türüne dönüştürmek için '{0}' örtük dönüştürmesini kullanır. https://aka.ms/fsharp-implicit-convs adresine bakın. Bu uyarı '#nowarn \"3391\" kullanılarak devre dışı bırakılabilir. + + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. 'InlineIfLambda' özniteliği yalnızca işlev veya F# temsilci türündeki yöntemlerin satır içine alınmış işlev parametrelerinde kullanılabilir. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 778f26de5e3..f05a5a897ce 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -697,6 +697,11 @@ 此表达式使用隐式转换“{0}”将类型“{1}”转换为类型“{2}”。请参阅 https://aka.ms/fsharp-implicit-convs。可使用 '#nowarn \"3391\" 禁用此警告。 + + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. "InlineIfLambda" 特性只能用于类型为函数或 F# 委托类型的方法的内联函数的参数。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 81e0c44f38b..e7bdda7e3ad 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -697,6 +697,11 @@ 此運算式使用隱含轉換 '{0}' 將類型 '{1}' 轉換為類型 '{2}'。請參閱 https://aka.ms/fsharp-implicit-convs。可使用 '#nowarn \"3391\" 停用此警告。 + + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Init-only property '{0}' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. 'InlineIfLambda' 屬性只能用於類型為函式或 F# 委派類型之方法的內嵌函式參數。 diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index a899d457f86..342ee526847 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -123,7 +123,6 @@ - @@ -158,8 +157,15 @@ + + %(RelativeDir)\TestSource\%(Filename)%(Extension) + + + %(RelativeDir)\TestSource\%(Filename)%(Extension) + - + + @@ -183,12 +189,6 @@ %(RelativeDir)\BaseLine\%(Filename)%(Extension) - - %(RelativeDir)\TestSource\%(Filename)%(Extension) - - - %(RelativeDir)\TestSource\%(Filename)%(Extension) - diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs new file mode 100644 index 00000000000..448c7b96648 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs @@ -0,0 +1,159 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. +namespace FSharp.Compiler.ComponentTests.Interop + +open Xunit +open FSharp.Test.Compiler +open FSharp.Test + +module ``Required and init-only properties`` = + + let withCSharpLanguageVersion (ver: CSharpLanguageVersion) (cUnit: CompilationUnit) : CompilationUnit = + match cUnit with + | CS cs -> CS { cs with LangVersion = ver } + | _ -> failwith "Only supported in C#" + + let csharpBaseClass = + CSharp """ + // Until we move to .NET7 runtime (or use experimental) + namespace System.Runtime.CompilerServices + { + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] + public sealed class RequiredMemberAttribute : Attribute { } + [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] + public sealed class CompilerFeatureRequiredAttribute : Attribute + { + public CompilerFeatureRequiredAttribute(string featureName) + { + FeatureName = featureName; + } + public string FeatureName { get; } + public bool IsOptional { get; init; } + public const string RefStructs = nameof(RefStructs); + public const string RequiredMembers = nameof(RequiredMembers); + } + } + + namespace RequiredAndInitOnlyProperties + { + public sealed class RAIO + { + public required int GetSet { get; set; } + public required int GetInit { get; init; } + } + + }""" |> withCSharpLanguageVersion CSharpLanguageVersion.Preview |> withName "csLib" + + + [] + let ``F# can init both set and init-only`` () = + + let csharpLib = csharpBaseClass + + let fsharpSource = + """ +open System +open RequiredAndInitOnlyProperties + +[] +let main _ = + + let raio = RAIO(GetSet = 1, GetInit = 2) + + if raio.GetSet <> 1 then + failwith $"Unexpected result %d{raio.GetSet}" + 0 +""" + FSharp fsharpSource + |> asExe + |> withLangVersionPreview + |> withReferences [csharpLib] + |> compileAndRun + |> shouldSucceed + + [] + let ``F# can change set property`` () = + + let csharpLib = csharpBaseClass + + let fsharpSource = + """ +open System +open RequiredAndInitOnlyProperties + +[] +let main _ = + + let raio = RAIO(GetSet = 1, GetInit = 2) + + if raio.GetSet <> 1 then + failwith $"Unexpected result %d{raio.GetSet}" + + raio.GetSet <- 0 + + if raio.GetSet <> 0 then + failwith $"Unexpected result %d{raio.GetSet}" + 0 +""" + FSharp fsharpSource + |> asExe + |> withLangVersionPreview + |> withReferences [csharpLib] + |> compileAndRun + |> shouldSucceed + + [] + let ``F# cannot change init-only property`` () = + + let csharpLib = csharpBaseClass + + let fsharpSource = + """ +open System +open RequiredAndInitOnlyProperties + +[] +let main _ = + + let raio = RAIO(GetSet = 1, GetInit = 2) + raio.GetInit <- 0 + + 0 +""" + FSharp fsharpSource + |> asExe + |> withLangVersionPreview + |> withReferences [csharpLib] + |> compile + |> shouldFail + |> withDiagnostics [ + Error 810, Line 9, Col 5, Line 9, Col 17, "Init-only property 'GetInit' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization" + ] + + + [] + let ``F# should produce compile-time error when required properties are not specified in the initializer`` () = + + let csharpLib = csharpBaseClass + + let fsharpSource = + """ +open System +open RequiredAndInitOnlyProperties + +[] +let main _ = + + let raio = RAIO(GetSet = 1, GetInit = 2) + raio.GetInit <- 0 + + 0 +""" + FSharp fsharpSource + |> asExe + |> withLangVersionPreview + |> withReferences [csharpLib] + |> compile + |> shouldFail + |> withDiagnostics [ + Error 810, Line 9, Col 5, Line 9, Col 17, "Init-only property 'GetInit' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization" + ] \ No newline at end of file diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/PropertyPages/ApplicationPropPageBase.vb b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/PropertyPages/ApplicationPropPageBase.vb index 981ae080b12..455679b2e4f 100644 --- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/PropertyPages/ApplicationPropPageBase.vb +++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/PropertyPages/ApplicationPropPageBase.vb @@ -8,6 +8,7 @@ Imports System.Collections Imports System.ComponentModel Imports System.Diagnostics Imports System.Drawing +Imports System.IO Imports System.Windows.Forms Imports System.Runtime.InteropServices @@ -328,7 +329,7 @@ Namespace Microsoft.VisualStudio.Editors.PropertyPages ' create the Image. Try Dim IconContents As Byte() = IO.File.ReadAllBytes(path) - Dim IconStream As New IO.MemoryStream(IconContents, 0, IconContents.Length) + Dim IconStream As New MemoryStream(IconContents, 0, IconContents.Length) ApplicationIconPictureBox.Image = IconToImage(New Icon(IconStream), ApplicationIconPictureBox.ClientSize) Catch ex As Exception Common.RethrowIfUnrecoverable(ex, True) diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/PropertyPages/DebugPropPage.vb b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/PropertyPages/DebugPropPage.vb index 5708fc56b74..3132379283e 100644 --- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/PropertyPages/DebugPropPage.vb +++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/PropertyPages/DebugPropPage.vb @@ -507,7 +507,7 @@ Namespace Microsoft.VisualStudio.Editors.PropertyPages If sInitialDirectory = "" Then Try sInitialDirectory = Path.Combine(GetDebugPathProjectPath(), GetSelectedConfigOutputPath()) - Catch ex As IO.IOException + Catch ex As IOException 'Ignore Catch ex As Exception Common.RethrowIfUnrecoverable(ex) From e2d9d689d12eec718974f7a853a973d7e6bb464f Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Mon, 11 Jul 2022 19:34:20 +0200 Subject: [PATCH 02/18] WIP: Separate tests --- .../Interop/RequiredAndInitOnlyProperties.fs | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs index 448c7b96648..4ebaa669cf2 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs @@ -12,8 +12,21 @@ module ``Required and init-only properties`` = | CS cs -> CS { cs with LangVersion = ver } | _ -> failwith "Only supported in C#" + let csharpBaseClass = CSharp """ + namespace RequiredAndInitOnlyProperties + { + public sealed class RAIO + { + public int GetSet { get; set; } + public int GetInit { get; init; } + } + + }""" |> withCSharpLanguageVersion CSharpLanguageVersion.Preview |> withName "csLib" + + let csharpRBaseClass = + CSharp """ // Until we move to .NET7 runtime (or use experimental) namespace System.Runtime.CompilerServices { @@ -133,7 +146,7 @@ let main _ = [] let ``F# should produce compile-time error when required properties are not specified in the initializer`` () = - let csharpLib = csharpBaseClass + let csharpLib = csharpRBaseClass let fsharpSource = """ @@ -143,8 +156,7 @@ open RequiredAndInitOnlyProperties [] let main _ = - let raio = RAIO(GetSet = 1, GetInit = 2) - raio.GetInit <- 0 + let raio = RAIO() 0 """ @@ -153,7 +165,4 @@ let main _ = |> withLangVersionPreview |> withReferences [csharpLib] |> compile - |> shouldFail - |> withDiagnostics [ - Error 810, Line 9, Col 5, Line 9, Col 17, "Init-only property 'GetInit' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization" - ] \ No newline at end of file + |> shouldSucceed \ No newline at end of file From 2a05ed2109c533325a59b476ca989a0245188b67 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Wed, 13 Jul 2022 19:02:03 +0200 Subject: [PATCH 03/18] Added check for explicit setters --- src/Compiler/Checking/CheckExpressions.fs | 13 +++ src/Compiler/FSComp.txt | 1 + src/Compiler/xlf/FSComp.txt.cs.xlf | 5 ++ src/Compiler/xlf/FSComp.txt.de.xlf | 5 ++ src/Compiler/xlf/FSComp.txt.es.xlf | 5 ++ src/Compiler/xlf/FSComp.txt.fr.xlf | 5 ++ src/Compiler/xlf/FSComp.txt.it.xlf | 5 ++ src/Compiler/xlf/FSComp.txt.ja.xlf | 5 ++ src/Compiler/xlf/FSComp.txt.ko.xlf | 5 ++ src/Compiler/xlf/FSComp.txt.pl.xlf | 5 ++ src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 5 ++ src/Compiler/xlf/FSComp.txt.ru.xlf | 5 ++ src/Compiler/xlf/FSComp.txt.tr.xlf | 5 ++ src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 5 ++ src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 5 ++ .../Interop/RequiredAndInitOnlyProperties.fs | 85 +++++++++++++++++++ 16 files changed, 164 insertions(+) diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 77736403c76..d797785636b 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -8964,6 +8964,19 @@ and TcLookupThen cenv overallTy env tpenv mObjExpr objExpr objExprTy longId dela // To get better warnings we special case some of the few known mutate-a-struct method names let mutates = (if methodName = "MoveNext" || methodName = "GetNextArg" then DefinitelyMutates else PossiblyMutates) + let minfo = List.head minfos + + // Check, wheter this method has `IsExternalInit`, emit an error diagnostic in this case. + let hasInitOnlyMod = + match minfo with + | ILMeth (_, ilMethInfo, _) -> + match ilMethInfo.ILMethodRef.ReturnType with + | ILType.Modified(_, cls, _) -> cls.FullName = "System.Runtime.CompilerServices.IsExternalInit" + | _ -> false + | _ -> false + if hasInitOnlyMod then + errorR (Error (FSComp.SR.tcGetterForInitOnlyPropertyCannotBeCalled1 methodName, mItem)) + #if !NO_TYPEPROVIDERS match TryTcMethodAppToStaticConstantArgs cenv env tpenv (minfos, tyArgsOpt, mExprAndItem, mItem) with | Some minfoAfterStaticArguments -> diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 4438faffcd4..08aa6e5f00d 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -653,6 +653,7 @@ tcExpressionWithIfRequiresParenthesis,"This list or array expression includes an 809,tcPropertyIsStatic,"Property '%s' is static" 810,tcPropertyCannotBeSet1,"Property '%s' cannot be set" 810,tcInitOnlyPropertyCannotBeSet1,"Init-only property '%s' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization" +810,tcGetterForInitOnlyPropertyCannotBeCalled1,"Cannot call '%s' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization" 811,tcConstructorsCannotBeFirstClassValues,"Constructors must be applied to arguments and cannot be used as first-class values. If necessary use an anonymous function '(fun arg1 ... argN -> new Type(arg1,...,argN))'." 812,tcSyntaxFormUsedOnlyWithRecordLabelsPropertiesAndFields,"The syntax 'expr.id' may only be used with record labels, properties and fields" 813,tcEventIsStatic,"Event '%s' is static" diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 0f49940c1ec..df859453a5c 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -662,6 +662,11 @@ Atributy nejde použít pro rozšíření typů. + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. Syntaxe expr1[expr2] se používá pro indexování. Pokud chcete povolit indexování, zvažte možnost přidat anotaci typu, nebo pokud voláte funkci, přidejte mezeru, třeba expr1 [expr2]. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 9632581132e..c0c38a50846 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -662,6 +662,11 @@ Attribute können nicht auf Typerweiterungen angewendet werden. + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. Die Syntax "expr1[expr2]" wird für die Indizierung verwendet. Fügen Sie ggf. eine Typanmerkung hinzu, um die Indizierung zu aktivieren, oder fügen Sie beim Aufrufen einer Funktion ein Leerzeichen hinzu, z. B. "expr1 [expr2]". diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 40c60110a03..9fba22358af 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -662,6 +662,11 @@ Los atributos no se pueden aplicar a las extensiones de tipo. + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. La sintaxis "expr1[expr2]" se usa para la indexación. Considere la posibilidad de agregar una anotación de tipo para habilitar la indexación, si se llama a una función, agregue un espacio, por ejemplo, "expr1 [expr2]". diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index c81fcbd170d..d87bac0dd8e 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -662,6 +662,11 @@ Impossible d'appliquer des attributs aux extensions de type. + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. La syntaxe « expr1[expr2] » est utilisée pour l’indexation. Envisagez d’ajouter une annotation de type pour activer l’indexation, ou si vous appelez une fonction, ajoutez un espace, par exemple « expr1 [expr2] ». diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 40b8c2baa9b..b8647861c8b 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -662,6 +662,11 @@ Gli attributi non possono essere applicati a estensioni di tipo. + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. La sintassi 'expr1[expr2]' viene usata per l'indicizzazione. Provare ad aggiungere un'annotazione di tipo per abilitare l'indicizzazione oppure se la chiamata a una funzione aggiunge uno spazio, ad esempio 'expr1 [expr2]'. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 2d3eb504a83..0d57ae7e023 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -662,6 +662,11 @@ 属性を型拡張に適用することはできません。 + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. 構文 'expr1[expr2]' はインデックス作成に使用されます。インデックスを有効にするために型の注釈を追加するか、関数を呼び出す場合には、'expr1 [expr2]' のようにスペースを入れます。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index b5933e98fdc..74f55d94463 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -662,6 +662,11 @@ 형식 확장에 특성을 적용할 수 없습니다. + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. 인덱싱에는 'expr1[expr2]' 구문이 사용됩니다. 인덱싱을 사용하도록 설정하기 위해 형식 주석을 추가하는 것을 고려하거나 함수를 호출하는 경우 공백을 추가하세요(예: 'expr1 [expr2]'). diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 17cca816ffd..d34a24f13f7 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -662,6 +662,11 @@ Atrybutów nie można stosować do rozszerzeń typu. + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. Do indeksowania używana jest składnia „expr1[expr2]”. Rozważ dodanie adnotacji typu, aby umożliwić indeksowanie, lub jeśli wywołujesz funkcję dodaj spację, np. „expr1 [expr2]”. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index d1eb2b66c4a..b3e61b9ca81 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -662,6 +662,11 @@ Os atributos não podem ser aplicados às extensões de tipo. + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. A sintaxe 'expr1[expr2]' é usada para indexação. Considere adicionar uma anotação de tipo para habilitar a indexação ou, se chamar uma função, adicione um espaço, por exemplo, 'expr1 [expr2]'. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 4975d0dbdd0..bff68499382 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -662,6 +662,11 @@ Атрибуты не могут быть применены к расширениям типа. + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. Для индексирования используется синтаксис "expr1[expr2]". Рассмотрите возможность добавления аннотации типа для включения индексации или при вызове функции добавьте пробел, например "expr1 [expr2]". diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 08722dc26f1..d34ddc2f8c1 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -662,6 +662,11 @@ Öznitelikler tür uzantılarına uygulanamaz. + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. Söz dizimi “expr1[expr2]” dizin oluşturma için kullanılıyor. Dizin oluşturmayı etkinleştirmek için bir tür ek açıklama eklemeyi düşünün veya bir işlev çağırıyorsanız bir boşluk ekleyin, örn. “expr1 [expr2]”. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index f05a5a897ce..e0d90c9e248 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -662,6 +662,11 @@ 属性不可应用于类型扩展。 + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. 语法“expr1[expr2]”用于索引。考虑添加类型批注来启用索引,或者在调用函数添加空格,例如“expr1 [expr2]”。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index e7bdda7e3ad..cbe53b2591a 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -662,6 +662,11 @@ 屬性無法套用到類型延伸模組。 + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. 語法 'expr1[expr2]' 已用於編製索引。請考慮新增類型註釋來啟用編製索引,或是呼叫函式並新增空格,例如 'expr1 [expr2]'。 diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs index 4ebaa669cf2..d1844ef334f 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs @@ -113,6 +113,63 @@ let main _ = |> withReferences [csharpLib] |> compileAndRun |> shouldSucceed + + [] + let ``F# can change set property via calling an explicit setter`` () = + + let csharpLib = csharpBaseClass + + let fsharpSource = + """ +open System +open RequiredAndInitOnlyProperties + +[] +let main _ = + + let raio = RAIO(GetSet = 1, GetInit = 2) + + if raio.GetSet <> 1 then + failwith $"Unexpected result %d{raio.GetSet}" + + raio.set_GetSet(0) + + if raio.GetSet <> 0 then + failwith $"Unexpected result %d{raio.GetSet}" + 0 +""" + FSharp fsharpSource + |> asExe + |> withLangVersionPreview + |> withReferences [csharpLib] + |> compileAndRun + |> shouldSucceed + + [] + let ``F# can get property via calling an explicit getter`` () = + + let csharpLib = csharpBaseClass + + let fsharpSource = + """ +open System +open RequiredAndInitOnlyProperties + +[] +let main _ = + + let raio = RAIO(GetSet = 1, GetInit = 2) + + if raio.get_GetSet <> 1 then + failwith $"Unexpected result %d{raio.GetSet}" + 0 +""" + FSharp fsharpSource + |> asExe + |> withLangVersionPreview + |> withReferences [csharpLib] + |> compileAndRun + |> shouldSucceed [] let ``F# cannot change init-only property`` () = @@ -142,6 +199,34 @@ let main _ = Error 810, Line 9, Col 5, Line 9, Col 17, "Init-only property 'GetInit' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization" ] + [] + let ``F# cannot change init-only property via calling an explicit setter`` () = + + let csharpLib = csharpBaseClass + + let fsharpSource = + """ +open System +open RequiredAndInitOnlyProperties + +[] +let main _ = + + let raio = RAIO(GetSet = 1, GetInit = 2) + raio.set_GetInit(0) + + 0 +""" + FSharp fsharpSource + |> asExe + |> withLangVersionPreview + |> withReferences [csharpLib] + |> compile + |> shouldFail + |> withDiagnostics [ + Error 810, Line 9, Col 5, Line 9, Col 21, "Cannot call 'set_GetInit' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization" + ] + [] let ``F# should produce compile-time error when required properties are not specified in the initializer`` () = From 8a7d48cada2793e0d80b564c6052d992a91e0112 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Wed, 13 Jul 2022 19:04:44 +0200 Subject: [PATCH 04/18] Fix tests --- .../Interop/RequiredAndInitOnlyProperties.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs index d1844ef334f..838ec719dd2 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs @@ -160,7 +160,7 @@ let main _ = let raio = RAIO(GetSet = 1, GetInit = 2) - if raio.get_GetSet <> 1 then + if raio.get_GetSet() <> 1 then failwith $"Unexpected result %d{raio.GetSet}" 0 """ From bdcab6b2030477e518d8825ee5095712b2174ce4 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Thu, 14 Jul 2022 15:37:30 +0200 Subject: [PATCH 05/18] Forbit calling setters on the methods --- src/Compiler/Checking/CheckExpressions.fs | 8 +++-- .../Interop/RequiredAndInitOnlyProperties.fs | 30 ++++++++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index d797785636b..b73cdcfe713 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -9741,7 +9741,7 @@ and TcMethodApplication // Build the expression that mutates the properties on the result of the call let setterExprPrebinders, propSetExpr = (mkUnit g mMethExpr, finalAssignedItemSetters) ||> List.mapFold (fun acc assignedItemSetter -> - let argExprPrebinder, action, m = TcSetterArgExpr cenv env denv objExpr ad assignedItemSetter + let argExprPrebinder, action, m = TcSetterArgExpr cenv env denv objExpr ad assignedItemSetter finalCalledMethInfo.IsConstructor argExprPrebinder, mkCompGenSequential m acc action) // now put them together @@ -9787,7 +9787,7 @@ and TcMethodApplication (callExpr6, finalAttributeAssignedNamedItems, delayed), tpenv /// For Method(X = expr) 'X' can be a property, IL Field or F# record field -and TcSetterArgExpr cenv env denv objExpr ad (AssignedItemSetter(id, setter, CallerArg(callerArgTy, m, isOptCallerArg, argExpr))) = +and TcSetterArgExpr cenv env denv objExpr ad (AssignedItemSetter(id, setter, CallerArg(callerArgTy, m, isOptCallerArg, argExpr))) calledFromConstructor = let g = cenv.g if isOptCallerArg then @@ -9796,6 +9796,10 @@ and TcSetterArgExpr cenv env denv objExpr ad (AssignedItemSetter(id, setter, Cal let argExprPrebinder, action, defnItem = match setter with | AssignedPropSetter (pinfo, pminfo, pminst) -> + + if pinfo.IsSetterInitOnly && not calledFromConstructor then + errorR (Error (FSComp.SR.tcInitOnlyPropertyCannotBeSet1 pinfo.PropertyName, m)) + MethInfoChecks g cenv.amap true None [objExpr] ad m pminfo let calledArgTy = List.head (List.head (pminfo.GetParamTypes(cenv.amap, m, pminst))) let tcVal = LightweightTcValForUsingInBuildMethodCall g diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs index 838ec719dd2..84329a780d3 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs @@ -21,6 +21,7 @@ module ``Required and init-only properties`` = { public int GetSet { get; set; } public int GetInit { get; init; } + public RAIO GetThis() => this; } }""" |> withCSharpLanguageVersion CSharpLanguageVersion.Preview |> withName "csLib" @@ -227,6 +228,33 @@ let main _ = Error 810, Line 9, Col 5, Line 9, Col 21, "Cannot call 'set_GetInit' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization" ] + [] + let ``F# cannot change init-only property via calling an initializer on instance`` () = + + let csharpLib = csharpBaseClass + + let fsharpSource = + """ +open System +open RequiredAndInitOnlyProperties + +[] +let main _ = + + let raio = RAIO() + raio.GetThis(GetSet=2, GetInit = 42) |> ignore + 0 +""" + FSharp fsharpSource + |> asExe + |> withLangVersionPreview + |> withReferences [csharpLib] + |> compile + |> shouldFail + |> withDiagnostics [ + Error 810, Line 9, Col 38, Line 9, Col 40, "Init-only property 'GetInit' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization" + ] + [] let ``F# should produce compile-time error when required properties are not specified in the initializer`` () = @@ -250,4 +278,4 @@ let main _ = |> withLangVersionPreview |> withReferences [csharpLib] |> compile - |> shouldSucceed \ No newline at end of file + |> shouldSucceed From 63fc2fb61d1422871beeaced5447e938166ffc0d Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Thu, 14 Jul 2022 19:12:23 +0200 Subject: [PATCH 06/18] wip: support required attributes --- src/Compiler/Checking/AttributeChecking.fs | 18 ++++++++++++++++-- src/Compiler/Checking/CheckExpressions.fs | 17 +++++++++++++++++ src/Compiler/Checking/infos.fs | 4 ++++ src/Compiler/Checking/infos.fsi | 3 +++ src/Compiler/FSComp.txt | 1 + src/Compiler/Facilities/LanguageFeatures.fs | 3 +++ src/Compiler/Facilities/LanguageFeatures.fsi | 1 + src/Compiler/TypedTree/TcGlobals.fs | 2 ++ src/Compiler/xlf/FSComp.txt.cs.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.de.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.es.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.fr.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.it.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.ja.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.ko.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.pl.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.ru.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.tr.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 5 +++++ 21 files changed, 112 insertions(+), 2 deletions(-) diff --git a/src/Compiler/Checking/AttributeChecking.fs b/src/Compiler/Checking/AttributeChecking.fs index 2439cc4f794..078360d4516 100644 --- a/src/Compiler/Checking/AttributeChecking.fs +++ b/src/Compiler/Checking/AttributeChecking.fs @@ -21,6 +21,8 @@ open FSharp.Compiler.TypeHierarchy #if !NO_TYPEPROVIDERS open FSharp.Compiler.TypeProviders open FSharp.Core.CompilerServices +open Features + #endif exception ObsoleteWarning of string * range @@ -236,8 +238,20 @@ let private CheckILAttributes (g: TcGlobals) isByrefLikeTyconRef cattrs m = | 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 - ErrorD (ObsoleteError(msg, m)) + if isError then + if g.langVersion.SupportsFeature(LanguageFeature.RequiredMembersSupport) then + // In some cases C# will generate both ObsoleteAttribute and CompilerFeatureRequiredAttribute. + // Specifically, when default constructor is generated for class with any reqired members in them. + // ObsoleteAttribute should be ignored if CompilerFeatureRequiredAttribute is present, and its name is "RequiredMembers". + // REVIEW: Shall feature names be moved to LanguageFeatures (or elsewhere), and be tied to actual features somehow? + let (AttribInfo(tref,_)) = g.attrib_CompilerFeatureRequiredAttribute + match TryDecodeILAttribute tref cattrs with + | Some([ILAttribElem.String (Some featureName) ], _) when featureName = "RequiredMembers" -> + CompleteD + | _ -> + ErrorD (ObsoleteError(msg, m)) + else + ErrorD (ObsoleteError(msg, m)) else WarnD (ObsoleteWarning(msg, m)) | Some ([ILAttribElem.String None ], _) when not isByrefLikeTyconRef -> diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index b73cdcfe713..397fbb7aa6e 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -9730,6 +9730,23 @@ and TcMethodApplication // Handle post-hoc property assignments let setterExprPrebinders, callExpr3 = let expr = callExpr2b + + // Make sure, if apparent type has any required properties, they all are in the `finalAssignedItemSetters`. + // If if is a constructor, and it is not marked with `SetsRequiredMembersAttributeAttribute`, then: + // 1. Get all properties of the type. + // 2. Check if any of them has `IsRequired` set. + // 2.1. If there are none, proceed as usual + // 2.2. If there are any, make sure all of them (or their setters) are in `finalAssignedItemSetters`. + // 3. If some are missing, produce a diagnostic which missing ones. + if g.langVersion.SupportsFeature(LanguageFeature.RequiredMembersSupport) && finalCalledMethInfo.IsConstructor then + let _requiredProps = + //&& (TryFindFSharpAttribute g.attrib_SetsRequiredMembersAttribute finalCalledMethInfo ) then [] + match finalCalledMethInfo with + | FSMeth (_, _enclosingType, _vref, _) -> [] // TODO: check if constructor has attrib_SetsRequiredMembersAttribute, then we don't required to init anything, otherwise check for props + | _ -> [] + + () + if isCheckingAttributeCall then [], expr elif isNil finalAssignedItemSetters then diff --git a/src/Compiler/Checking/infos.fs b/src/Compiler/Checking/infos.fs index 4e71ee9ea01..62582d6ec31 100644 --- a/src/Compiler/Checking/infos.fs +++ b/src/Compiler/Checking/infos.fs @@ -1582,6 +1582,10 @@ type ILPropInfo = (x.HasGetter && x.GetterMethod.IsNewSlot) || (x.HasSetter && x.SetterMethod.IsNewSlot) + member _.IsRequired = + //x.RawMetadata.Attributes + false + /// Get the names and types of the indexer arguments associated with the IL property. /// /// Any type parameters of the enclosing type are instantiated in the type returned. diff --git a/src/Compiler/Checking/infos.fsi b/src/Compiler/Checking/infos.fsi index 97dc3d74c04..c31115d6111 100644 --- a/src/Compiler/Checking/infos.fsi +++ b/src/Compiler/Checking/infos.fsi @@ -695,6 +695,9 @@ type ILPropInfo = /// Get the declaring IL type of the IL property, including any generic instantiation member ILTypeInfo: ILTypeInfo + /// Is the property requied (has the RequiredMemberAttribute). + member IsRequired: bool + /// Indicates if the IL property is logically a 'newslot', i.e. hides any previous slots of the same name. member IsNewSlot: bool diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 08aa6e5f00d..e23691c1522 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1545,6 +1545,7 @@ featureStructActivePattern,"struct representation for active patterns" featureRelaxWhitespace2,"whitespace relaxation v2" featureReallyLongList,"list literals of any size" featureErrorOnDeprecatedRequireQualifiedAccess,"give error on deprecated access of construct with RequireQualifiedAccess attribute" +featureRequiredMembers,"support for required type members" 3353,fsiInvalidDirective,"Invalid directive '#%s %s'" 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/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index a0033a5d2b7..000937e3403 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -49,6 +49,7 @@ type LanguageFeature = | DelegateTypeNameResolutionFix | ReallyLongLists | ErrorOnDeprecatedRequireQualifiedAccess + | RequiredMembersSupport /// LanguageVersion management type LanguageVersion(versionText) = @@ -111,6 +112,7 @@ type LanguageVersion(versionText) = LanguageFeature.BetterExceptionPrinting, previewVersion LanguageFeature.ReallyLongLists, previewVersion LanguageFeature.ErrorOnDeprecatedRequireQualifiedAccess, previewVersion + LanguageFeature.RequiredMembersSupport, previewVersion ] static let defaultLanguageVersion = LanguageVersion("default") @@ -210,6 +212,7 @@ type LanguageVersion(versionText) = | LanguageFeature.DelegateTypeNameResolutionFix -> FSComp.SR.featureDelegateTypeNameResolutionFix () | LanguageFeature.ReallyLongLists -> FSComp.SR.featureReallyLongList () | LanguageFeature.ErrorOnDeprecatedRequireQualifiedAccess -> FSComp.SR.featureErrorOnDeprecatedRequireQualifiedAccess () + | LanguageFeature.RequiredMembersSupport -> FSComp.SR.featureRequiredMembers () /// Get a version string associated with the given feature. member _.GetFeatureVersionString feature = diff --git a/src/Compiler/Facilities/LanguageFeatures.fsi b/src/Compiler/Facilities/LanguageFeatures.fsi index ec884903b49..bcee72d3562 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -39,6 +39,7 @@ type LanguageFeature = | DelegateTypeNameResolutionFix | ReallyLongLists | ErrorOnDeprecatedRequireQualifiedAccess + | RequiredMembersSupport /// LanguageVersion management type LanguageVersion = diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index 51060755e80..8a5ef3e0133 100755 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -1425,6 +1425,8 @@ type TcGlobals( member val attrib_SecurityCriticalAttribute = findSysAttrib "System.Security.SecurityCriticalAttribute" member val attrib_SecuritySafeCriticalAttribute = findSysAttrib "System.Security.SecuritySafeCriticalAttribute" member val attrib_ComponentModelEditorBrowsableAttribute = findSysAttrib "System.ComponentModel.EditorBrowsableAttribute" + member val attrib_CompilerFeatureRequiredAttribute = findSysAttrib "System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute" + member val attrib_SetsRequiredMembersAttribute = findSysAttrib "System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute" member g.improveType tcref tinst = improveTy tcref tinst diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index df859453a5c..17669a8c837 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -252,6 +252,11 @@ relaxace whitespace v2 + + support for required type members + support for required type members + + resumable state machines obnovitelné stavové stroje diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index c0c38a50846..b03e898d6b0 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -252,6 +252,11 @@ whitespace relaxation v2 + + support for required type members + support for required type members + + resumable state machines Fortsetzbarer Zustand-Maschinen diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 9fba22358af..88dcac9757a 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -252,6 +252,11 @@ relajación de espacios en blanco v2 + + support for required type members + support for required type members + + resumable state machines máquinas de estado reanudables diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index d87bac0dd8e..af92d6f3d3e 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -252,6 +252,11 @@ relaxation des espaces blancs v2 + + support for required type members + support for required type members + + resumable state machines ordinateurs d’état pouvant être repris diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index b8647861c8b..f0c969fc210 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -252,6 +252,11 @@ uso meno restrittivo degli spazi vuoti v2 + + support for required type members + support for required type members + + resumable state machines macchine a stati ripristinabili diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 0d57ae7e023..b3f484f33a1 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -252,6 +252,11 @@ whitespace relaxation v2 + + support for required type members + support for required type members + + resumable state machines 再開可能なステート マシン diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 74f55d94463..0e9fdc450d4 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -252,6 +252,11 @@ 공백 relaxation v2 + + support for required type members + support for required type members + + resumable state machines 다시 시작 가능한 상태 시스템 diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index d34a24f13f7..25b19f71794 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -252,6 +252,11 @@ łagodzenie odstępów wer 2 + + support for required type members + support for required type members + + resumable state machines automaty stanów z możliwością wznowienia diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index b3e61b9ca81..4fbb5fc4360 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -252,6 +252,11 @@ relaxamento de espaço em branco v2 + + support for required type members + support for required type members + + resumable state machines máquinas de estado retomável diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index bff68499382..d814f0c58be 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -252,6 +252,11 @@ смягчение требований по использованию пробелов, версия 2 + + support for required type members + support for required type members + + resumable state machines возобновляемые конечные автоматы diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index d34ddc2f8c1..bed6387ca82 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -252,6 +252,11 @@ boşluk ilişkilendirme v2 + + support for required type members + support for required type members + + resumable state machines sürdürülebilir durum makineleri diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index e0d90c9e248..123b6948fb2 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -252,6 +252,11 @@ 空格放空 v2 + + support for required type members + support for required type members + + resumable state machines 可恢复状态机 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index cbe53b2591a..93fb74d3f74 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -252,6 +252,11 @@ 空格鍵放鬆 v2 + + support for required type members + support for required type members + + resumable state machines 可繼續的狀態機器 From b1ffb44a0383f395eebd67ae04df7743819be063 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Fri, 15 Jul 2022 19:03:34 +0200 Subject: [PATCH 07/18] Added required properties support + apply fantomas --- src/Compiler/Checking/AttributeChecking.fs | 2 +- src/Compiler/Checking/CheckExpressions.fs | 53 ++++++++++------ src/Compiler/Checking/NicePrint.fs | 14 +++++ src/Compiler/Checking/NicePrint.fsi | 5 ++ src/Compiler/Checking/infos.fs | 13 ++-- src/Compiler/Checking/infos.fsi | 3 + src/Compiler/FSComp.txt | 4 +- src/Compiler/Facilities/LanguageFeatures.fs | 9 ++- src/Compiler/Facilities/LanguageFeatures.fsi | 3 +- src/Compiler/TypedTree/TcGlobals.fs | 1 + src/Compiler/xlf/FSComp.txt.cs.xlf | 16 ++++- src/Compiler/xlf/FSComp.txt.de.xlf | 16 ++++- src/Compiler/xlf/FSComp.txt.es.xlf | 16 ++++- src/Compiler/xlf/FSComp.txt.fr.xlf | 16 ++++- src/Compiler/xlf/FSComp.txt.it.xlf | 16 ++++- src/Compiler/xlf/FSComp.txt.ja.xlf | 16 ++++- src/Compiler/xlf/FSComp.txt.ko.xlf | 16 ++++- src/Compiler/xlf/FSComp.txt.pl.xlf | 16 ++++- src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 16 ++++- src/Compiler/xlf/FSComp.txt.ru.xlf | 16 ++++- src/Compiler/xlf/FSComp.txt.tr.xlf | 16 ++++- src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 16 ++++- src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 16 ++++- .../Interop/RequiredAndInitOnlyProperties.fs | 62 ++++++++++++++++++- 24 files changed, 308 insertions(+), 69 deletions(-) diff --git a/src/Compiler/Checking/AttributeChecking.fs b/src/Compiler/Checking/AttributeChecking.fs index 078360d4516..ca7786c8817 100644 --- a/src/Compiler/Checking/AttributeChecking.fs +++ b/src/Compiler/Checking/AttributeChecking.fs @@ -239,7 +239,7 @@ let private CheckILAttributes (g: TcGlobals) isByrefLikeTyconRef cattrs m = WarnD(ObsoleteWarning(msg, m)) | Some ([ILAttribElem.String (Some msg); ILAttribElem.Bool isError ], _) when not isByrefLikeTyconRef -> if isError then - if g.langVersion.SupportsFeature(LanguageFeature.RequiredMembersSupport) then + if g.langVersion.SupportsFeature(LanguageFeature.RequiredPropertiesSupport) then // In some cases C# will generate both ObsoleteAttribute and CompilerFeatureRequiredAttribute. // Specifically, when default constructor is generated for class with any reqired members in them. // ObsoleteAttribute should be ignored if CompilerFeatureRequiredAttribute is present, and its name is "RequiredMembers". diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 397fbb7aa6e..969246ad13a 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -8964,18 +8964,19 @@ and TcLookupThen cenv overallTy env tpenv mObjExpr objExpr objExprTy longId dela // To get better warnings we special case some of the few known mutate-a-struct method names let mutates = (if methodName = "MoveNext" || methodName = "GetNextArg" then DefinitelyMutates else PossiblyMutates) - let minfo = List.head minfos - - // Check, wheter this method has `IsExternalInit`, emit an error diagnostic in this case. - let hasInitOnlyMod = - match minfo with - | ILMeth (_, ilMethInfo, _) -> - match ilMethInfo.ILMethodRef.ReturnType with - | ILType.Modified(_, cls, _) -> cls.FullName = "System.Runtime.CompilerServices.IsExternalInit" + if g.langVersion.SupportsFeature(LanguageFeature.InitPropertiesSupport) then + let minfo = List.head minfos + + // Check, wheter this method has `IsExternalInit`, emit an error diagnostic in this case. + let hasInitOnlyMod = + match minfo with + | ILMeth (_, ilMethInfo, _) -> + match ilMethInfo.ILMethodRef.ReturnType with + | ILType.Modified(_, cls, _) -> cls.FullName = "System.Runtime.CompilerServices.IsExternalInit" + | _ -> false | _ -> false - | _ -> false - if hasInitOnlyMod then - errorR (Error (FSComp.SR.tcGetterForInitOnlyPropertyCannotBeCalled1 methodName, mItem)) + if hasInitOnlyMod then + errorR (Error (FSComp.SR.tcGetterForInitOnlyPropertyCannotBeCalled1 methodName, mItem)) #if !NO_TYPEPROVIDERS match TryTcMethodAppToStaticConstantArgs cenv env tpenv (minfos, tyArgsOpt, mExprAndItem, mItem) with @@ -9024,7 +9025,7 @@ and TcLookupThen cenv overallTy env tpenv mObjExpr objExpr objExprTy longId dela TcMethodApplicationThen cenv env overallTy None tpenv tyArgsOpt objArgs mExprAndItem mItem nm ad PossiblyMutates true meths afterResolution NormalValUse args atomicFlag delayed else - if pinfo.IsSetterInitOnly then + if g.langVersion.SupportsFeature(LanguageFeature.RequiredPropertiesSupport) && pinfo.IsSetterInitOnly then errorR (Error (FSComp.SR.tcInitOnlyPropertyCannotBeSet1 nm, mItem)) let args = if pinfo.IsIndexer then args else [] @@ -9738,14 +9739,28 @@ and TcMethodApplication // 2.1. If there are none, proceed as usual // 2.2. If there are any, make sure all of them (or their setters) are in `finalAssignedItemSetters`. // 3. If some are missing, produce a diagnostic which missing ones. - if g.langVersion.SupportsFeature(LanguageFeature.RequiredMembersSupport) && finalCalledMethInfo.IsConstructor then - let _requiredProps = - //&& (TryFindFSharpAttribute g.attrib_SetsRequiredMembersAttribute finalCalledMethInfo ) then [] + if g.langVersion.SupportsFeature(LanguageFeature.RequiredPropertiesSupport) && finalCalledMethInfo.IsConstructor then + let requiredProps = match finalCalledMethInfo with - | FSMeth (_, _enclosingType, _vref, _) -> [] // TODO: check if constructor has attrib_SetsRequiredMembersAttribute, then we don't required to init anything, otherwise check for props + | ILMeth (_, ilmethInfo, _) -> + if TryFindILAttribute g.attrib_SetsRequiredMembersAttribute ilmethInfo.RawMetadata.CustomAttrs then + [] + else + let props = GetImmediateIntrinsicPropInfosOfType (None, AccessibleFromSomeFSharpCode) g cenv.amap range0 ilmethInfo.ApparentEnclosingType + List.filter (fun (p: PropInfo) -> p.IsRequired ) props | _ -> [] - - () + + if requiredProps.Length > 0 then + let setterPropNames = + finalAssignedItemSetters + |> List.choose (function | AssignedItemSetter(_, AssignedPropSetter (pinfo, _, _), _) -> Some pinfo.PropertyName | _ -> None) + + let missingProps = + requiredProps + |> List.filter (fun pinfo -> not (List.contains pinfo.PropertyName setterPropNames)) + if missingProps.Length > 0 then + let details = NicePrint.multiLineStringOfPropInfos g cenv.amap mMethExpr env.DisplayEnv missingProps + errorR(Error(FSComp.SR.tcMissingRequiredMembers details, mMethExpr)) if isCheckingAttributeCall then [], expr @@ -9814,7 +9829,7 @@ and TcSetterArgExpr cenv env denv objExpr ad (AssignedItemSetter(id, setter, Cal match setter with | AssignedPropSetter (pinfo, pminfo, pminst) -> - if pinfo.IsSetterInitOnly && not calledFromConstructor then + if g.langVersion.SupportsFeature(LanguageFeature.RequiredPropertiesSupport) && pinfo.IsSetterInitOnly && not calledFromConstructor then errorR (Error (FSComp.SR.tcInitOnlyPropertyCannotBeSet1 pinfo.PropertyName, m)) MethInfoChecks g cenv.amap true None [objExpr] ad m pminfo diff --git a/src/Compiler/Checking/NicePrint.fs b/src/Compiler/Checking/NicePrint.fs index 3a398620de9..0088da73d72 100644 --- a/src/Compiler/Checking/NicePrint.fs +++ b/src/Compiler/Checking/NicePrint.fs @@ -1552,6 +1552,10 @@ module InfoMemberPrinting = layoutType denv retTy ^^ getterSetter + let formatPropInfoToBufferFreeStyle g amap m denv os (pinfo: PropInfo) = + let resL = prettyLayoutOfPropInfoFreeStyle g amap m denv pinfo + resL |> bufferL os + let formatMethInfoToBufferFreeStyle amap m denv os (minfo: MethInfo) = let _, resL = prettyLayoutOfMethInfoFreeStyle amap m denv emptyTyparInst minfo resL |> bufferL os @@ -2461,6 +2465,16 @@ let multiLineStringOfMethInfos infoReader m denv minfos = |> List.map (sprintf "%s %s" Environment.NewLine) |> String.concat "" +let stringOfPropInfo g amap m denv pinfo = + buildString (fun buf -> InfoMemberPrinting.formatPropInfoToBufferFreeStyle g amap m denv buf pinfo) + +/// Convert PropInfos to lines separated by newline including a newline as the first character +let multiLineStringOfPropInfos g amap m denv pinfos = + pinfos + |> List.map (stringOfPropInfo g amap m denv) + |> List.map (sprintf "%s %s" Environment.NewLine) + |> String.concat "" + /// Convert a ParamData to a string let stringOfParamData denv paramData = buildString (fun buf -> InfoMemberPrinting.formatParamDataToBuffer denv buf paramData) diff --git a/src/Compiler/Checking/NicePrint.fsi b/src/Compiler/Checking/NicePrint.fsi index c9df76a87a7..504d5c6a727 100644 --- a/src/Compiler/Checking/NicePrint.fsi +++ b/src/Compiler/Checking/NicePrint.fsi @@ -82,6 +82,11 @@ val stringOfMethInfo: infoReader: InfoReader -> m: range -> denv: DisplayEnv -> val multiLineStringOfMethInfos: infoReader: InfoReader -> m: range -> denv: DisplayEnv -> minfos: MethInfo list -> string +val stringOfPropInfo: g: TcGlobals -> amap: ImportMap -> m: range -> denv: DisplayEnv -> pinfo: PropInfo -> string + +val multiLineStringOfPropInfos: + g: TcGlobals -> amap: ImportMap -> m: range -> denv: DisplayEnv -> pinfos: PropInfo list -> string + val stringOfParamData: denv: DisplayEnv -> paramData: ParamData -> string val layoutOfParamData: denv: DisplayEnv -> paramData: ParamData -> Layout diff --git a/src/Compiler/Checking/infos.fs b/src/Compiler/Checking/infos.fs index 62582d6ec31..8a65315af57 100644 --- a/src/Compiler/Checking/infos.fs +++ b/src/Compiler/Checking/infos.fs @@ -1567,7 +1567,6 @@ type ILPropInfo = match x.SetterMethod.ILMethodRef.ReturnType with | ILType.Modified(_, cls, _) -> cls.FullName = "System.Runtime.CompilerServices.IsExternalInit" | _ -> false - /// tcref.CompiledRepresentationForNamedType.BasicQualifiedName = "System.ReadOnlySpan`1" /// Indicates if the IL property is static member x.IsStatic = (x.RawMetadata.CallingConv = ILThisConvention.Static) @@ -1582,9 +1581,7 @@ type ILPropInfo = (x.HasGetter && x.GetterMethod.IsNewSlot) || (x.HasSetter && x.SetterMethod.IsNewSlot) - member _.IsRequired = - //x.RawMetadata.Attributes - false + member x.IsRequired = TryFindILAttribute x.TcGlobals.attrib_RequiredMemberAttribute x.RawMetadata.CustomAttrs /// Get the names and types of the indexer arguments associated with the IL property. /// @@ -1707,6 +1704,14 @@ type PropInfo = | ProvidedProp _ -> false #endif + member x.IsRequired = + match x with + | ILProp ilpinfo -> ilpinfo.IsRequired + | FSProp _ -> false +#if !NO_TYPEPROVIDERS + | ProvidedProp _ -> false +#endif + /// Indicates if this is an extension member member x.IsExtensionMember = match x.ArbitraryValRef with diff --git a/src/Compiler/Checking/infos.fsi b/src/Compiler/Checking/infos.fsi index c31115d6111..ecc8df4f4a2 100644 --- a/src/Compiler/Checking/infos.fsi +++ b/src/Compiler/Checking/infos.fsi @@ -793,6 +793,9 @@ type PropInfo = /// Indidcates whether IL property has an init-only setter (i.e. has the `System.Runtime.CompilerServices.IsExternalInit` modifer) member IsSetterInitOnly: bool + /// Is the property requied (has the RequiredMemberAttribute). + member IsRequired: bool + member ImplementedSlotSignatures: SlotSig list /// Indicates if this property is marked 'override' and thus definitely overrides another property. diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index e23691c1522..65316b8498f 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1545,7 +1545,8 @@ featureStructActivePattern,"struct representation for active patterns" featureRelaxWhitespace2,"whitespace relaxation v2" featureReallyLongList,"list literals of any size" featureErrorOnDeprecatedRequireQualifiedAccess,"give error on deprecated access of construct with RequireQualifiedAccess attribute" -featureRequiredMembers,"support for required type members" +featureRequiredProperties,"support for required properties" +featureInitProperties,"support for consuming init properties" 3353,fsiInvalidDirective,"Invalid directive '#%s %s'" 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." @@ -1635,3 +1636,4 @@ reprStateMachineInvalidForm,"The state machine has an unexpected form" 3522,tcAnonRecdDuplicateFieldId,"The field '%s' appears multiple times in this record expression." 3523,tcAnonRecdTypeDuplicateFieldId,"The field '%s' appears multiple times in this anonymous record type." 3524,parsExpectingExpressionInTuple,"Expecting expression" +3545,tcMissingRequiredMembers,"The following required properties have to be initalized:%s" \ No newline at end of file diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index 000937e3403..a67668080ef 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -49,7 +49,8 @@ type LanguageFeature = | DelegateTypeNameResolutionFix | ReallyLongLists | ErrorOnDeprecatedRequireQualifiedAccess - | RequiredMembersSupport + | RequiredPropertiesSupport + | InitPropertiesSupport /// LanguageVersion management type LanguageVersion(versionText) = @@ -112,7 +113,8 @@ type LanguageVersion(versionText) = LanguageFeature.BetterExceptionPrinting, previewVersion LanguageFeature.ReallyLongLists, previewVersion LanguageFeature.ErrorOnDeprecatedRequireQualifiedAccess, previewVersion - LanguageFeature.RequiredMembersSupport, previewVersion + LanguageFeature.RequiredPropertiesSupport, previewVersion + LanguageFeature.InitPropertiesSupport, previewVersion ] static let defaultLanguageVersion = LanguageVersion("default") @@ -212,7 +214,8 @@ type LanguageVersion(versionText) = | LanguageFeature.DelegateTypeNameResolutionFix -> FSComp.SR.featureDelegateTypeNameResolutionFix () | LanguageFeature.ReallyLongLists -> FSComp.SR.featureReallyLongList () | LanguageFeature.ErrorOnDeprecatedRequireQualifiedAccess -> FSComp.SR.featureErrorOnDeprecatedRequireQualifiedAccess () - | LanguageFeature.RequiredMembersSupport -> FSComp.SR.featureRequiredMembers () + | LanguageFeature.RequiredPropertiesSupport -> FSComp.SR.featureRequiredProperties () + | LanguageFeature.InitPropertiesSupport -> FSComp.SR.featureInitProperties () /// Get a version string associated with the given feature. member _.GetFeatureVersionString feature = diff --git a/src/Compiler/Facilities/LanguageFeatures.fsi b/src/Compiler/Facilities/LanguageFeatures.fsi index bcee72d3562..eece3fd377c 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -39,7 +39,8 @@ type LanguageFeature = | DelegateTypeNameResolutionFix | ReallyLongLists | ErrorOnDeprecatedRequireQualifiedAccess - | RequiredMembersSupport + | RequiredPropertiesSupport + | InitPropertiesSupport /// LanguageVersion management type LanguageVersion = diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index 8a5ef3e0133..f5924c5f8fb 100755 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -1427,6 +1427,7 @@ type TcGlobals( member val attrib_ComponentModelEditorBrowsableAttribute = findSysAttrib "System.ComponentModel.EditorBrowsableAttribute" member val attrib_CompilerFeatureRequiredAttribute = findSysAttrib "System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute" member val attrib_SetsRequiredMembersAttribute = findSysAttrib "System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute" + member val attrib_RequiredMemberAttribute = findSysAttrib "System.Runtime.CompilerServices.RequiredMemberAttribute" member g.improveType tcref tinst = improveTy tcref tinst diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 17669a8c837..93110b7d46a 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -187,6 +187,11 @@ Notace expr[idx] pro indexování a vytváření řezů + + support for consuming init properties + support for consuming init properties + + interfaces with multiple generic instantiation rozhraní s vícenásobným obecným vytvářením instancí @@ -252,9 +257,9 @@ relaxace whitespace v2 - - support for required type members - support for required type members + + support for required properties + support for required properties @@ -777,6 +782,11 @@ K hodnotě označené jako literál se {0} nedá přiřadit. + + The following required properties have to be initalized:{0} + The following required properties have to be initalized:{0} + + Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:6.0 or later Použití metod s atributem NoEagerConstraintApplicationAttribute vyžaduje /langversion:6.0 nebo novější. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index b03e898d6b0..4f944f8194d 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -187,6 +187,11 @@ expr[idx]-Notation zum Indizieren und Aufteilen + + support for consuming init properties + support for consuming init properties + + interfaces with multiple generic instantiation Schnittstellen mit mehrfacher generischer Instanziierung @@ -252,9 +257,9 @@ whitespace relaxation v2 - - support for required type members - support for required type members + + support for required properties + support for required properties @@ -777,6 +782,11 @@ "{0}" kann keinem als Literal markierten Wert zugewiesen werden. + + The following required properties have to be initalized:{0} + The following required properties have to be initalized:{0} + + Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:6.0 or later Die Verwendung von Methoden mit "NoEagerConstraintApplicationAttribute" erfordert /langversion:6.0 oder höher. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 88dcac9757a..49d77bdff20 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -187,6 +187,11 @@ Notación para indexación y segmentación expr[idx] + + support for consuming init properties + support for consuming init properties + + interfaces with multiple generic instantiation interfaces con creación de instancias genéricas múltiples @@ -252,9 +257,9 @@ relajación de espacios en blanco v2 - - support for required type members - support for required type members + + support for required properties + support for required properties @@ -777,6 +782,11 @@ No se puede asignar "{0}" a un valor marcado como literal + + The following required properties have to be initalized:{0} + The following required properties have to be initalized:{0} + + Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:6.0 or later El uso de métodos con "NoEagerConstraintApplicationAttribute" requiere /langversion:6.0 o posteriores diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index af92d6f3d3e..675610670da 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -187,6 +187,11 @@ Notation expr[idx] pour l’indexation et le découpage + + support for consuming init properties + support for consuming init properties + + interfaces with multiple generic instantiation interfaces avec plusieurs instanciations génériques @@ -252,9 +257,9 @@ relaxation des espaces blancs v2 - - support for required type members - support for required type members + + support for required properties + support for required properties @@ -777,6 +782,11 @@ Impossible d'affecter '{0}' à une valeur marquée comme littérale + + The following required properties have to be initalized:{0} + The following required properties have to be initalized:{0} + + Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:6.0 or later L’utilisation de méthodes avec « NoEagerConstraintApplicationAttribute » requiert/langversion:6.0 ou ultérieur diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index f0c969fc210..a8793133747 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -187,6 +187,11 @@ Notazione expr[idx] per l'indicizzazione e il sezionamento + + support for consuming init properties + support for consuming init properties + + interfaces with multiple generic instantiation interfacce con più creazioni di istanze generiche @@ -252,9 +257,9 @@ uso meno restrittivo degli spazi vuoti v2 - - support for required type members - support for required type members + + support for required properties + support for required properties @@ -777,6 +782,11 @@ Non è possibile assegnare '{0}' a un valore contrassegnato come letterale + + The following required properties have to be initalized:{0} + The following required properties have to be initalized:{0} + + Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:6.0 or later L'utilizzo di metodi con 'NoEagerConstraintApplicationAttribute' richiede /langversion: 6.0 o versione successiva diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index b3f484f33a1..c1c22e5256b 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -187,6 +187,11 @@ インデックス作成とスライス用の expr[idx] 表記 + + support for consuming init properties + support for consuming init properties + + interfaces with multiple generic instantiation 複数のジェネリックのインスタンス化を含むインターフェイス @@ -252,9 +257,9 @@ whitespace relaxation v2 - - support for required type members - support for required type members + + support for required properties + support for required properties @@ -777,6 +782,11 @@ リテラルとしてマークされた値に '{0}' を割り当てることはできません + + The following required properties have to be initalized:{0} + The following required properties have to be initalized:{0} + + Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:6.0 or later 'NoEagerConstraintApplicationAttribute' を指定してメソッドを使用するには、/langversion:6.0 以降が必要です diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 0e9fdc450d4..eb937a60fdc 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -187,6 +187,11 @@ 인덱싱 및 슬라이싱을 위한 expr[idx] 표기법 + + support for consuming init properties + support for consuming init properties + + interfaces with multiple generic instantiation 여러 제네릭 인스턴스화가 포함된 인터페이스 @@ -252,9 +257,9 @@ 공백 relaxation v2 - - support for required type members - support for required type members + + support for required properties + support for required properties @@ -777,6 +782,11 @@ 리터럴로 표시된 값에 '{0}'을(를) 할당할 수 없습니다. + + The following required properties have to be initalized:{0} + The following required properties have to be initalized:{0} + + Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:6.0 or later 'NoEagerConstraintApplicationAttribute'와 함께 메서드를 사용하려면 /langversion:6.0 이상이 필요합니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 25b19f71794..753201ce9b5 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -187,6 +187,11 @@ notacja wyrażenia expr[idx] do indeksowania i fragmentowania + + support for consuming init properties + support for consuming init properties + + interfaces with multiple generic instantiation interfejsy z wieloma ogólnymi wystąpieniami @@ -252,9 +257,9 @@ łagodzenie odstępów wer 2 - - support for required type members - support for required type members + + support for required properties + support for required properties @@ -777,6 +782,11 @@ Nie można przypisać elementu „{0}” do wartości oznaczonej jako literał + + The following required properties have to be initalized:{0} + The following required properties have to be initalized:{0} + + Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:6.0 or later Używanie metod z atrybutem "NoEagerConstraintApplicationAttribute" wymaga parametru /langversion:6.0 lub nowszego diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 4fbb5fc4360..1ccb2706e97 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -187,6 +187,11 @@ notação expr[idx] para indexação e fatia + + support for consuming init properties + support for consuming init properties + + interfaces with multiple generic instantiation interfaces com várias instanciações genéricas @@ -252,9 +257,9 @@ relaxamento de espaço em branco v2 - - support for required type members - support for required type members + + support for required properties + support for required properties @@ -777,6 +782,11 @@ Não é possível atribuir '{0}' a um valor marcado como literal + + The following required properties have to be initalized:{0} + The following required properties have to be initalized:{0} + + Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:6.0 or later Usar métodos com 'NoEagerConstraintApplicationAttribute' requer /langversion:6.0 ou posterior diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index d814f0c58be..7fad9552855 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -187,6 +187,11 @@ expr[idx] для индексации и среза + + support for consuming init properties + support for consuming init properties + + interfaces with multiple generic instantiation интерфейсы с множественным универсальным созданием экземпляра @@ -252,9 +257,9 @@ смягчение требований по использованию пробелов, версия 2 - - support for required type members - support for required type members + + support for required properties + support for required properties @@ -777,6 +782,11 @@ Невозможно присвоить "{0}" значению, помеченному как литерал + + The following required properties have to be initalized:{0} + The following required properties have to be initalized:{0} + + Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:6.0 or later Для использования методов с "NoEagerConstraintApplicationAttribute" требуется /langversion:6.0 или более поздняя версия diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index bed6387ca82..3feb6c39261 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -187,6 +187,11 @@ Dizin oluşturma ve dilimleme için expr[idx] gösterimi + + support for consuming init properties + support for consuming init properties + + interfaces with multiple generic instantiation birden çok genel örnek oluşturma içeren arabirimler @@ -252,9 +257,9 @@ boşluk ilişkilendirme v2 - - support for required type members - support for required type members + + support for required properties + support for required properties @@ -777,6 +782,11 @@ Sabit değer olarak işaretlenen bir değere '{0}' atanamaz + + The following required properties have to be initalized:{0} + The following required properties have to be initalized:{0} + + Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:6.0 or later 'NoEagerConstraintApplicationAttribute' içeren yöntemlerin kullanılması /langversion:6.0 veya üstünü gerektiriyor diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 123b6948fb2..455b1918080 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -187,6 +187,11 @@ 用于索引和切片的 expr[idx] 表示法 + + support for consuming init properties + support for consuming init properties + + interfaces with multiple generic instantiation 具有多个泛型实例化的接口 @@ -252,9 +257,9 @@ 空格放空 v2 - - support for required type members - support for required type members + + support for required properties + support for required properties @@ -777,6 +782,11 @@ 无法将“{0}”分配给标记为文本的值 + + The following required properties have to be initalized:{0} + The following required properties have to be initalized:{0} + + Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:6.0 or later 将方法与 “NoEagerConstraintApplicationAttribute” 配合使用需要 /langversion:6.0 或更高版本 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 93fb74d3f74..7ba08af1b09 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -187,6 +187,11 @@ 用於編製索引和分割的 expr[idx] 註釋 + + support for consuming init properties + support for consuming init properties + + interfaces with multiple generic instantiation 具有多個泛型具現化的介面 @@ -252,9 +257,9 @@ 空格鍵放鬆 v2 - - support for required type members - support for required type members + + support for required properties + support for required properties @@ -777,6 +782,11 @@ 無法將 '{0}' 指派給標記為常值的值 + + The following required properties have to be initalized:{0} + The following required properties have to be initalized:{0} + + Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:6.0 or later 使用具有 'NoEagerConstraintApplicationAttribute' 的方法需要 /langversion:6.0 或更新版本 diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs index 84329a780d3..b026d6f6d4c 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs @@ -4,6 +4,7 @@ namespace FSharp.Compiler.ComponentTests.Interop open Xunit open FSharp.Test.Compiler open FSharp.Test +open System module ``Required and init-only properties`` = @@ -278,4 +279,63 @@ let main _ = |> withLangVersionPreview |> withReferences [csharpLib] |> compile - |> shouldSucceed + |> shouldFail + |> withDiagnostics [ + Error 3545, Line 8, Col 16, Line 8, Col 22, "The following required properties have to be initalized:" + Environment.NewLine + " property RAIO.GetSet: int with get, set" + Environment.NewLine + " property RAIO.GetInit: int with get, set" + ] + + [] + let ``F# should produce compile-time error when some required properties are not specified in the initializer`` () = + + let csharpLib = csharpRBaseClass + + let fsharpSource = + """ +open System +open RequiredAndInitOnlyProperties + +[] +let main _ = + + let raio = RAIO(GetSet=1) + + 0 +""" + FSharp fsharpSource + |> asExe + |> withLangVersionPreview + |> withReferences [csharpLib] + |> compile + |> shouldFail + |> withDiagnostics [ + Error 3545, Line 8, Col 16, Line 8, Col 30, "The following required properties have to be initalized:" + Environment.NewLine + " property RAIO.GetInit: int with get, set" + ] + + [] + let ``F# should not produce compile-time error when all required properties are specified in the initializer`` () = + + let csharpLib = csharpRBaseClass + + let fsharpSource = + """ +open System +open RequiredAndInitOnlyProperties + +[] +let main _ = + + let raio = RAIO(GetSet=1, GetInit=2) + + if raio.GetSet <> 1 then + failwith "Unexpected value" + + if raio.GetInit <> 2 then + failwith "Unexpected value" + 0 +""" + FSharp fsharpSource + |> asExe + |> withLangVersionPreview + |> withReferences [csharpLib] + |> compileAndRun + |> shouldSucceed \ No newline at end of file From 2681745caeecc6f46d8a75037ccdb04b090beb9a Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Fri, 22 Jul 2022 14:31:42 +0200 Subject: [PATCH 08/18] Moved compilerfeaturerequired check to a method --- src/Compiler/Checking/AttributeChecking.fs | 38 ++++++++++++---------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/Compiler/Checking/AttributeChecking.fs b/src/Compiler/Checking/AttributeChecking.fs index 03bed907ee4..7731b83c256 100644 --- a/src/Compiler/Checking/AttributeChecking.fs +++ b/src/Compiler/Checking/AttributeChecking.fs @@ -231,34 +231,36 @@ let MethInfoHasAttribute g m attribSpec minfo = |> 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 reqired members in them. + // ObsoleteAttribute should be ignored if CompilerFeatureRequiredAttribute is present, and its name is "RequiredMembers". + let (AttribInfo(tref,_)) = g.attrib_CompilerFeatureRequiredAttribute + match TryDecodeILAttribute tref cattrs with + | Some([ILAttribElem.String (Some featureName) ], _) when featureName = "RequiredMembers" -> + CompleteD + | _ -> + ErrorD (ObsoleteError(msg, m)) + /// Check IL attributes for 'ObsoleteAttribute', returning errors and warnings as data -let private CheckILAttributes (g: TcGlobals) isByrefLikeTyconRef cattrs m = +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 -> + 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 -> + | Some ([ILAttribElem.String (Some msg); ILAttribElem.Bool isError ], _) when not isByrefLikeTyconRef -> if isError then if g.langVersion.SupportsFeature(LanguageFeature.RequiredPropertiesSupport) then - // In some cases C# will generate both ObsoleteAttribute and CompilerFeatureRequiredAttribute. - // Specifically, when default constructor is generated for class with any reqired members in them. - // ObsoleteAttribute should be ignored if CompilerFeatureRequiredAttribute is present, and its name is "RequiredMembers". - // REVIEW: Shall feature names be moved to LanguageFeatures (or elsewhere), and be tied to actual features somehow? - let (AttribInfo(tref,_)) = g.attrib_CompilerFeatureRequiredAttribute - match TryDecodeILAttribute tref cattrs with - | Some([ILAttribElem.String (Some featureName) ], _) when featureName = "RequiredMembers" -> - CompleteD - | _ -> - ErrorD (ObsoleteError(msg, m)) + CheckCompilerFeatureRequiredAttribute g cattrs msg m else ErrorD (ObsoleteError(msg, m)) - else + else WarnD (ObsoleteWarning(msg, m)) - | Some ([ILAttribElem.String None ], _) when not isByrefLikeTyconRef -> + | Some ([ILAttribElem.String None ], _) when not isByrefLikeTyconRef -> WarnD(ObsoleteWarning("", m)) - | Some _ when not isByrefLikeTyconRef -> + | Some _ when not isByrefLikeTyconRef -> WarnD(ObsoleteWarning("", m)) - | _ -> + | _ -> CompleteD let langVersionPrefix = "--langversion:preview" From 81da22c8a339adbcb694f1d79b4595cc5a45879c Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Fri, 22 Jul 2022 19:04:27 +0200 Subject: [PATCH 09/18] Updated --- src/Compiler/AbstractIL/il.fs | 5 +- src/Compiler/AbstractIL/il.fsi | 2 + src/Compiler/Checking/CheckExpressions.fs | 80 +++++++++---------- src/Compiler/Checking/infos.fs | 19 ++++- src/Compiler/Checking/infos.fsi | 6 ++ src/Compiler/FSComp.txt | 2 +- src/Compiler/TypedTree/TcGlobals.fs | 2 +- src/Compiler/xlf/FSComp.txt.cs.xlf | 10 +-- src/Compiler/xlf/FSComp.txt.de.xlf | 10 +-- src/Compiler/xlf/FSComp.txt.es.xlf | 10 +-- src/Compiler/xlf/FSComp.txt.fr.xlf | 10 +-- src/Compiler/xlf/FSComp.txt.it.xlf | 10 +-- src/Compiler/xlf/FSComp.txt.ja.xlf | 10 +-- src/Compiler/xlf/FSComp.txt.ko.xlf | 10 +-- src/Compiler/xlf/FSComp.txt.pl.xlf | 10 +-- src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 10 +-- src/Compiler/xlf/FSComp.txt.ru.xlf | 10 +-- src/Compiler/xlf/FSComp.txt.tr.xlf | 10 +-- src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 10 +-- src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 10 +-- .../Interop/RequiredAndInitOnlyProperties.fs | 40 ++++++++++ 21 files changed, 174 insertions(+), 112 deletions(-) diff --git a/src/Compiler/AbstractIL/il.fs b/src/Compiler/AbstractIL/il.fs index 2321a26bf05..d228356cbab 100644 --- a/src/Compiler/AbstractIL/il.fs +++ b/src/Compiler/AbstractIL/il.fs @@ -1203,10 +1203,11 @@ type ILAttribute = [] type ILAttributes(array: ILAttribute[]) = + member _.AsArray() = array - member x.AsArray() = array + member _.AsList() = array |> Array.toList - member x.AsList() = array |> Array.toList + static member Empty with get () = ILAttributes([||]) [] type ILAttributesStored = diff --git a/src/Compiler/AbstractIL/il.fsi b/src/Compiler/AbstractIL/il.fsi index 12067f8911c..ef88575602f 100644 --- a/src/Compiler/AbstractIL/il.fsi +++ b/src/Compiler/AbstractIL/il.fsi @@ -855,6 +855,8 @@ type ILAttributes = member AsList: unit -> ILAttribute list + static member Empty: ILAttributes + /// Represents the efficiency-oriented storage of ILAttributes in another item. [] type ILAttributesStored diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 7729f3a26c6..93cafc36e93 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -1497,6 +1497,42 @@ let CheckForAbnormalOperatorNames (cenv: cenv) (idRange: range) coreDisplayName warning(StandardOperatorRedefinitionWarning(FSComp.SR.tcInvalidMemberNameFixedTypes opName, idRange)) | Other -> () +let CheckInitProperties (g: TcGlobals) (minfo: MethInfo) methodName mItem = + if g.langVersion.SupportsFeature(LanguageFeature.InitPropertiesSupport) then + // Check, wheter this method has external init, emit an error diagnostic in this case. + if minfo.HasExternalInit then + errorR (Error (FSComp.SR.tcSetterForInitOnlyPropertyCannotBeCalled1 methodName, mItem)) + +let CheckRequiredProps (g:TcGlobals) (env: TcEnv) (cenv: TcFileState) (minfo: MethInfo) finalAssignedItemSetters mMethExpr = + // Make sure, if apparent type has any required properties, they all are in the `finalAssignedItemSetters`. + // If if is a constructor, and it is not marked with `SetsRequiredMembersAttributeAttribute`, then: + // 1. Get all properties of the type. + // 2. Check if any of them has `IsRequired` set. + // 2.1. If there are none, proceed as usual + // 2.2. If there are any, make sure all of them (or their setters) are in `finalAssignedItemSetters`. + // 3. If some are missing, produce a diagnostic which missing ones. + if g.langVersion.SupportsFeature(LanguageFeature.RequiredPropertiesSupport) && minfo.IsConstructor then + let requiredProps = + [ + if not (TryFindILAttribute g.attrib_SetsRequiredMembersAttribute (minfo.GetCustomAttrs())) then + let props = GetImmediateIntrinsicPropInfosOfType (None, AccessibleFromSomeFSharpCode) g cenv.amap range0 minfo.ApparentEnclosingType + for prop in props do + if prop.IsRequired then + prop + ] + + if requiredProps.Length > 0 then + let setterPropNames = + finalAssignedItemSetters + |> List.choose (function | AssignedItemSetter(_, AssignedPropSetter (pinfo, _, _), _) -> Some pinfo.PropertyName | _ -> None) + + let missingProps = + requiredProps + |> List.filter (fun pinfo -> not (List.contains pinfo.PropertyName setterPropNames)) + if missingProps.Length > 0 then + let details = NicePrint.multiLineStringOfPropInfos g cenv.amap mMethExpr env.DisplayEnv missingProps + errorR(Error(FSComp.SR.tcMissingRequiredMembers details, mMethExpr)) + let MakeAndPublishVal (cenv: cenv) env (altActualParent, inSig, declKind, valRecInfo, vscheme, attrs, xmlDoc, konst, isGeneratedEventVal) = let g = cenv.g @@ -8978,19 +9014,7 @@ and TcLookupThen cenv overallTy env tpenv mObjExpr objExpr objExprTy longId dela // To get better warnings we special case some of the few known mutate-a-struct method names let mutates = (if methodName = "MoveNext" || methodName = "GetNextArg" then DefinitelyMutates else PossiblyMutates) - if g.langVersion.SupportsFeature(LanguageFeature.InitPropertiesSupport) then - let minfo = List.head minfos - - // Check, wheter this method has `IsExternalInit`, emit an error diagnostic in this case. - let hasInitOnlyMod = - match minfo with - | ILMeth (_, ilMethInfo, _) -> - match ilMethInfo.ILMethodRef.ReturnType with - | ILType.Modified(_, cls, _) -> cls.FullName = "System.Runtime.CompilerServices.IsExternalInit" - | _ -> false - | _ -> false - if hasInitOnlyMod then - errorR (Error (FSComp.SR.tcGetterForInitOnlyPropertyCannotBeCalled1 methodName, mItem)) + CheckInitProperties g (List.head minfos) methodName mItem #if !NO_TYPEPROVIDERS match TryTcMethodAppToStaticConstantArgs cenv env tpenv (minfos, tyArgsOpt, mExprAndItem, mItem) with @@ -9746,35 +9770,7 @@ and TcMethodApplication let setterExprPrebinders, callExpr3 = let expr = callExpr2b - // Make sure, if apparent type has any required properties, they all are in the `finalAssignedItemSetters`. - // If if is a constructor, and it is not marked with `SetsRequiredMembersAttributeAttribute`, then: - // 1. Get all properties of the type. - // 2. Check if any of them has `IsRequired` set. - // 2.1. If there are none, proceed as usual - // 2.2. If there are any, make sure all of them (or their setters) are in `finalAssignedItemSetters`. - // 3. If some are missing, produce a diagnostic which missing ones. - if g.langVersion.SupportsFeature(LanguageFeature.RequiredPropertiesSupport) && finalCalledMethInfo.IsConstructor then - let requiredProps = - match finalCalledMethInfo with - | ILMeth (_, ilmethInfo, _) -> - if TryFindILAttribute g.attrib_SetsRequiredMembersAttribute ilmethInfo.RawMetadata.CustomAttrs then - [] - else - let props = GetImmediateIntrinsicPropInfosOfType (None, AccessibleFromSomeFSharpCode) g cenv.amap range0 ilmethInfo.ApparentEnclosingType - List.filter (fun (p: PropInfo) -> p.IsRequired ) props - | _ -> [] - - if requiredProps.Length > 0 then - let setterPropNames = - finalAssignedItemSetters - |> List.choose (function | AssignedItemSetter(_, AssignedPropSetter (pinfo, _, _), _) -> Some pinfo.PropertyName | _ -> None) - - let missingProps = - requiredProps - |> List.filter (fun pinfo -> not (List.contains pinfo.PropertyName setterPropNames)) - if missingProps.Length > 0 then - let details = NicePrint.multiLineStringOfPropInfos g cenv.amap mMethExpr env.DisplayEnv missingProps - errorR(Error(FSComp.SR.tcMissingRequiredMembers details, mMethExpr)) + CheckRequiredProps g env cenv finalCalledMethInfo finalAssignedItemSetters mMethExpr if isCheckingAttributeCall then [], expr diff --git a/src/Compiler/Checking/infos.fs b/src/Compiler/Checking/infos.fs index 7e477fcfaed..9876089ad76 100644 --- a/src/Compiler/Checking/infos.fs +++ b/src/Compiler/Checking/infos.fs @@ -22,6 +22,8 @@ open FSharp.Compiler.Xml #if !NO_TYPEPROVIDERS open FSharp.Compiler.TypeProviders +open FSharp.Compiler.AbstractIL + #endif //------------------------------------------------------------------------- @@ -933,6 +935,15 @@ type MethInfo = | FSMeth _ -> false // F# defined methods not supported yet. Must be a language feature. | _ -> false + /// Indicates, wheter this method has `IsExternalInit` modreq. + member x.HasExternalInit = + match x with + | ILMeth (_, ilMethInfo, _) -> + match ilMethInfo.ILMethodRef.ReturnType with + | ILType.Modified(_, cls, _) -> cls.FullName = "System.Runtime.CompilerServices.IsExternalInit" + | _ -> false + | _ -> false + /// Indicates if this method is an extension member that is read-only. /// An extension member is considered read-only if the first argument is a read-only byref (inref) type. member x.IsReadOnlyExtensionMember (amap: ImportMap, m) = @@ -1053,6 +1064,12 @@ type MethInfo = else [] #endif + /// Get custom attributes for method (only applicable for IL methods) + member x.GetCustomAttrs() = + match x with + | ILMeth(_, ilMethInfo, _) -> ilMethInfo.RawMetadata.CustomAttrs + | _ -> ILAttributes.Empty + /// Get the parameter attributes of a method info, which get combined with the parameter names and types member x.GetParamAttribs(amap, m) = match x with @@ -2287,4 +2304,4 @@ let PropInfosEquivByNameAndSig erasureFlag g amap m (pinfo: PropInfo) (pinfo2: P let SettersOfPropInfos (pinfos: PropInfo list) = pinfos |> List.choose (fun pinfo -> if pinfo.HasSetter then Some(pinfo.SetterMethod, Some pinfo) else None) -let GettersOfPropInfos (pinfos: PropInfo list) = pinfos |> List.choose (fun pinfo -> if pinfo.HasGetter then Some(pinfo.GetterMethod, Some pinfo) else None) +let GettersOfPropInfos (pinfos: PropInfo list) = pinfos |> List.choose (fun pinfo -> if pinfo.HasGetter then Some(pinfo.GetterMethod, Some pinfo) else None) \ No newline at end of file diff --git a/src/Compiler/Checking/infos.fsi b/src/Compiler/Checking/infos.fsi index ecc8df4f4a2..9d4fd965a67 100644 --- a/src/Compiler/Checking/infos.fsi +++ b/src/Compiler/Checking/infos.fsi @@ -423,6 +423,9 @@ type MethInfo = /// Receiver must be a struct type. member IsReadOnly: bool + /// Indicates, wheter this method has `IsExternalInit` modreq. + member HasExternalInit: bool + /// Indicates if the enclosing type for the method is a value type. /// /// For an extension method, this indicates if the method extends a struct type. @@ -493,6 +496,9 @@ type MethInfo = /// An instance method returns one object argument. member GetObjArgTypes: amap: ImportMap * m: range * minst: TypeInst -> TType list + /// Get custom attributes for method (only applicable for IL methods) + member GetCustomAttrs: unit -> ILAttributes + /// Get the parameter attributes of a method info, which get combined with the parameter names and types member GetParamAttribs: amap: ImportMap * m: range -> (bool * bool * bool * OptionalArgInfo * CallerInfo * ReflectedArgInfo) list list diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index c76a45a06a7..60e5702d449 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -653,7 +653,7 @@ tcExpressionWithIfRequiresParenthesis,"This list or array expression includes an 809,tcPropertyIsStatic,"Property '%s' is static" 810,tcPropertyCannotBeSet1,"Property '%s' cannot be set" 810,tcInitOnlyPropertyCannotBeSet1,"Init-only property '%s' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization" -810,tcGetterForInitOnlyPropertyCannotBeCalled1,"Cannot call '%s' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization" +810,tcSetterForInitOnlyPropertyCannotBeCalled1,"Cannot call '%s' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization" 811,tcConstructorsCannotBeFirstClassValues,"Constructors must be applied to arguments and cannot be used as first-class values. If necessary use an anonymous function '(fun arg1 ... argN -> new Type(arg1,...,argN))'." 812,tcSyntaxFormUsedOnlyWithRecordLabelsPropertiesAndFields,"The syntax 'expr.id' may only be used with record labels, properties and fields" 813,tcEventIsStatic,"Event '%s' is static" diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index 4597bc6fa1c..7eaf2ecbd18 100755 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -1427,7 +1427,7 @@ type TcGlobals( member val attrib_ComponentModelEditorBrowsableAttribute = findSysAttrib "System.ComponentModel.EditorBrowsableAttribute" member val attrib_CompilerFeatureRequiredAttribute = findSysAttrib "System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute" member val attrib_SetsRequiredMembersAttribute = findSysAttrib "System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute" - member val attrib_RequiredMemberAttribute = findSysAttrib "System.Runtime.CompilerServices.RequiredMemberAttribute" + member val attrib_RequiredMemberAttribute = findSysAttrib "System.Runtime.CompilerServices.RequiredMemberAttribute" member g.improveType tcref tinst = improveTy tcref tinst diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index b42d599f68a..8052182cecb 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -682,11 +682,6 @@ Atributy nejde použít pro rozšíření typů. - - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - - The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. Syntaxe expr1[expr2] se používá pro indexování. Pokud chcete povolit indexování, zvažte možnost přidat anotaci typu, nebo pokud voláte funkci, přidejte mezeru, třeba expr1 [expr2]. @@ -877,6 +872,11 @@ Použití obnovitelného kódu nebo obnovitelných stavových strojů vyžaduje /langversion:preview. + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. Tento výraz implicitně převede typ {0} na typ {1}. Přečtěte si téma https://aka.ms/fsharp-implicit-convs. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 6ef86ef82ed..3d3dc8c2604 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -682,11 +682,6 @@ Attribute können nicht auf Typerweiterungen angewendet werden. - - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - - The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. Die Syntax "expr1[expr2]" wird für die Indizierung verwendet. Fügen Sie ggf. eine Typanmerkung hinzu, um die Indizierung zu aktivieren, oder fügen Sie beim Aufrufen einer Funktion ein Leerzeichen hinzu, z. B. "expr1 [expr2]". @@ -877,6 +872,11 @@ Die Verwendung von Fortsetzbarem Code oder fortsetzbaren Zustandscomputern erfordert /langversion:preview + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. Dieser Ausdruck konvertiert den Typ "{0}" implizit in den Typ "{1}". Siehe https://aka.ms/fsharp-implicit-convs. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 8290feb7524..ba19316436e 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -682,11 +682,6 @@ Los atributos no se pueden aplicar a las extensiones de tipo. - - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - - The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. La sintaxis "expr1[expr2]" se usa para la indexación. Considere la posibilidad de agregar una anotación de tipo para habilitar la indexación, si se llama a una función, agregue un espacio, por ejemplo, "expr1 [expr2]". @@ -877,6 +872,11 @@ El uso de código reanudable o de máquinas de estado reanudables requiere /langversion:preview + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. Esta expresión convierte implícitamente el tipo '{0}' al tipo '{1}'. Consulte https://aka.ms/fsharp-implicit-convs. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index adbb4e6182e..4ed2c0da2a9 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -682,11 +682,6 @@ Impossible d'appliquer des attributs aux extensions de type. - - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - - The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. La syntaxe « expr1[expr2] » est utilisée pour l’indexation. Envisagez d’ajouter une annotation de type pour activer l’indexation, ou si vous appelez une fonction, ajoutez un espace, par exemple « expr1 [expr2] ». @@ -877,6 +872,11 @@ L’utilisation de code pouvant être repris ou de machines d’état pouvant être reprises nécessite /langversion:preview + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. Cette expression convertit implicitement le type « {0} » en type « {1} ». Voir https://aka.ms/fsharp-implicit-convs. diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 9e4ed52e546..01af391840a 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -682,11 +682,6 @@ Gli attributi non possono essere applicati a estensioni di tipo. - - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - - The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. La sintassi 'expr1[expr2]' viene usata per l'indicizzazione. Provare ad aggiungere un'annotazione di tipo per abilitare l'indicizzazione oppure se la chiamata a una funzione aggiunge uno spazio, ad esempio 'expr1 [expr2]'. @@ -877,6 +872,11 @@ Per l'uso del codice ripristinabile o delle macchine a stati ripristinabili è richiesto /langversion:preview + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. Questa espressione converte in modo implicito il tipo '{0}' nel tipo '{1}'. Vedere https://aka.ms/fsharp-implicit-convs. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 0484483c072..54fbab4b514 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -682,11 +682,6 @@ 属性を型拡張に適用することはできません。 - - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - - The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. 構文 'expr1[expr2]' はインデックス作成に使用されます。インデックスを有効にするために型の注釈を追加するか、関数を呼び出す場合には、'expr1 [expr2]' のようにスペースを入れます。 @@ -877,6 +872,11 @@ 再開可能なコードまたは再開可能なステート マシンを使用するには、/langversion:preview が必要です + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. この式は、型 '{0}' を型 '{1}' に暗黙的に変換します。https://aka.ms/fsharp-implicit-convs を参照してください。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index a3d591bd2f7..7ed437b2763 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -682,11 +682,6 @@ 형식 확장에 특성을 적용할 수 없습니다. - - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - - The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. 인덱싱에는 'expr1[expr2]' 구문이 사용됩니다. 인덱싱을 사용하도록 설정하기 위해 형식 주석을 추가하는 것을 고려하거나 함수를 호출하는 경우 공백을 추가하세요(예: 'expr1 [expr2]'). @@ -877,6 +872,11 @@ 다시 시작 가능한 코드 또는 다시 시작 가능한 상태 시스템을 사용하려면 /langversion:preview가 필요합니다. + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. 이 식은 암시적으로 '{0}' 형식을 '{1}' 형식으로 변환 합니다. https://aka.ms/fsharp-implicit-convs 참조 diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 50b0cde2d34..19e01c91485 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -682,11 +682,6 @@ Atrybutów nie można stosować do rozszerzeń typu. - - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - - The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. Do indeksowania używana jest składnia „expr1[expr2]”. Rozważ dodanie adnotacji typu, aby umożliwić indeksowanie, lub jeśli wywołujesz funkcję dodaj spację, np. „expr1 [expr2]”. @@ -877,6 +872,11 @@ Używanie kodu z możliwością wznowienia lub automatów stanów z możliwością wznowienia wymaga parametru /langversion: wersja zapoznawcza + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. To wyrażenie bezwzględnie konwertuje typ "{0}" na typ "{1}". Zobacz https://aka.ms/fsharp-implicit-convs. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 1db31fe74e1..615e716bd0f 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -682,11 +682,6 @@ Os atributos não podem ser aplicados às extensões de tipo. - - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - - The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. A sintaxe 'expr1[expr2]' é usada para indexação. Considere adicionar uma anotação de tipo para habilitar a indexação ou, se chamar uma função, adicione um espaço, por exemplo, 'expr1 [expr2]'. @@ -877,6 +872,11 @@ Usar código retomável ou máquinas de estado retomável requer /langversion:preview + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. Essa expressão converte implicitamente o tipo '{0}' ao tipo '{1}'. Consulte https://aka.ms/fsharp-implicit-convs. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 1a58b9316a8..f534378e99f 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -682,11 +682,6 @@ Атрибуты не могут быть применены к расширениям типа. - - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - - The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. Для индексирования используется синтаксис "expr1[expr2]". Рассмотрите возможность добавления аннотации типа для включения индексации или при вызове функции добавьте пробел, например "expr1 [expr2]". @@ -877,6 +872,11 @@ Для использования возобновляемого кода или возобновляемых конечных автоматов требуется /langversion:preview + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. Это выражение неявно преобразует тип "{0}" в тип "{1}". См. сведения на странице https://aka.ms/fsharp-implicit-convs. diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index c3567c5877a..70335d09d9d 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -682,11 +682,6 @@ Öznitelikler tür uzantılarına uygulanamaz. - - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - - The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. Söz dizimi “expr1[expr2]” dizin oluşturma için kullanılıyor. Dizin oluşturmayı etkinleştirmek için bir tür ek açıklama eklemeyi düşünün veya bir işlev çağırıyorsanız bir boşluk ekleyin, örn. “expr1 [expr2]”. @@ -877,6 +872,11 @@ Sürdürülebilir kod veya sürdürülebilir durum makinelerini kullanmak için /langversion:preview gerekir + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. Bu ifade '{0}' türünü örtülü olarak '{1}' türüne dönüştürür. https://aka.ms/fsharp-implicit-convs adresine bakın. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 1dedf7e59a6..4e7e55a375c 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -682,11 +682,6 @@ 属性不可应用于类型扩展。 - - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - - The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. 语法“expr1[expr2]”用于索引。考虑添加类型批注来启用索引,或者在调用函数添加空格,例如“expr1 [expr2]”。 @@ -877,6 +872,11 @@ 使用可恢复代码或可恢复状态机需要 /langversion:preview + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. 此表达式将类型“{0}”隐式转换为类型“{1}”。请参阅 https://aka.ms/fsharp-implicit-convs。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 05e48744e8f..965a9c231b6 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -682,11 +682,6 @@ 屬性無法套用到類型延伸模組。 - - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization - - The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. 語法 'expr1[expr2]' 已用於編製索引。請考慮新增類型註釋來啟用編製索引,或是呼叫函式並新增空格,例如 'expr1 [expr2]'。 @@ -877,6 +872,11 @@ 使用可繼續的程式碼或可繼續的狀態機器需要 /langversion:preview + + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + Cannot call '{0}' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. 此運算式將類型 '{0}' 隱含轉換為類型 '{1}'。請參閱 https://aka.ms/fsharp-implicit-convs。 diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs index b026d6f6d4c..25e69517378 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs @@ -59,7 +59,11 @@ module ``Required and init-only properties`` = }""" |> withCSharpLanguageVersion CSharpLanguageVersion.Preview |> withName "csLib" +#if !NETCOREAPP + [] +#else [] +#endif let ``F# can init both set and init-only`` () = let csharpLib = csharpBaseClass @@ -85,7 +89,11 @@ let main _ = |> compileAndRun |> shouldSucceed +#if !NETCOREAPP + [] +#else [] +#endif let ``F# can change set property`` () = let csharpLib = csharpBaseClass @@ -116,7 +124,11 @@ let main _ = |> compileAndRun |> shouldSucceed +#if !NETCOREAPP + [] +#else [] +#endif let ``F# can change set property via calling an explicit setter`` () = let csharpLib = csharpBaseClass @@ -147,7 +159,11 @@ let main _ = |> compileAndRun |> shouldSucceed +#if !NETCOREAPP + [] +#else [] +#endif let ``F# can get property via calling an explicit getter`` () = let csharpLib = csharpBaseClass @@ -173,7 +189,11 @@ let main _ = |> compileAndRun |> shouldSucceed +#if !NETCOREAPP + [] +#else [] +#endif let ``F# cannot change init-only property`` () = let csharpLib = csharpBaseClass @@ -201,7 +221,11 @@ let main _ = Error 810, Line 9, Col 5, Line 9, Col 17, "Init-only property 'GetInit' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization" ] +#if !NETCOREAPP + [] +#else [] +#endif let ``F# cannot change init-only property via calling an explicit setter`` () = let csharpLib = csharpBaseClass @@ -229,7 +253,11 @@ let main _ = Error 810, Line 9, Col 5, Line 9, Col 21, "Cannot call 'set_GetInit' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization" ] + #if !NETCOREAPP + [] +#else [] +#endif let ``F# cannot change init-only property via calling an initializer on instance`` () = let csharpLib = csharpBaseClass @@ -257,7 +285,11 @@ let main _ = ] +#if !NETCOREAPP + [] +#else [] +#endif let ``F# should produce compile-time error when required properties are not specified in the initializer`` () = let csharpLib = csharpRBaseClass @@ -284,7 +316,11 @@ let main _ = Error 3545, Line 8, Col 16, Line 8, Col 22, "The following required properties have to be initalized:" + Environment.NewLine + " property RAIO.GetSet: int with get, set" + Environment.NewLine + " property RAIO.GetInit: int with get, set" ] + #if !NETCOREAPP + [] +#else [] +#endif let ``F# should produce compile-time error when some required properties are not specified in the initializer`` () = let csharpLib = csharpRBaseClass @@ -311,7 +347,11 @@ let main _ = Error 3545, Line 8, Col 16, Line 8, Col 30, "The following required properties have to be initalized:" + Environment.NewLine + " property RAIO.GetInit: int with get, set" ] + #if !NETCOREAPP + [] +#else [] +#endif let ``F# should not produce compile-time error when all required properties are specified in the initializer`` () = let csharpLib = csharpRBaseClass From 662186fbc652e2ac389f1cc2ee951ac27b7d88d7 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Fri, 22 Jul 2022 19:08:53 +0200 Subject: [PATCH 10/18] fantomas --- src/Compiler/AbstractIL/il.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler/AbstractIL/il.fs b/src/Compiler/AbstractIL/il.fs index d228356cbab..dbeadc43aa0 100644 --- a/src/Compiler/AbstractIL/il.fs +++ b/src/Compiler/AbstractIL/il.fs @@ -1207,7 +1207,7 @@ type ILAttributes(array: ILAttribute[]) = member _.AsList() = array |> Array.toList - static member Empty with get () = ILAttributes([||]) + static member Empty = ILAttributes([||]) [] type ILAttributesStored = From 005af55664ea4809f80368c4f8c8d9892fb871b5 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Fri, 22 Jul 2022 19:39:12 +0200 Subject: [PATCH 11/18] Internalize empty --- src/Compiler/AbstractIL/il.fs | 2 +- src/Compiler/AbstractIL/il.fsi | 2 +- .../Interop/RequiredAndInitOnlyProperties.fs | 37 ++++++++++++++++++- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/Compiler/AbstractIL/il.fs b/src/Compiler/AbstractIL/il.fs index dbeadc43aa0..aa06532ce1c 100644 --- a/src/Compiler/AbstractIL/il.fs +++ b/src/Compiler/AbstractIL/il.fs @@ -1207,7 +1207,7 @@ type ILAttributes(array: ILAttribute[]) = member _.AsList() = array |> Array.toList - static member Empty = ILAttributes([||]) + static member internal Empty = ILAttributes([||]) [] type ILAttributesStored = diff --git a/src/Compiler/AbstractIL/il.fsi b/src/Compiler/AbstractIL/il.fsi index ef88575602f..8b5a3160c06 100644 --- a/src/Compiler/AbstractIL/il.fsi +++ b/src/Compiler/AbstractIL/il.fsi @@ -855,7 +855,7 @@ type ILAttributes = member AsList: unit -> ILAttribute list - static member Empty: ILAttributes + static member internal Empty: ILAttributes /// Represents the efficiency-oriented storage of ILAttributes in another item. [] diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs index 25e69517378..ea7b40bcaaa 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs @@ -316,7 +316,7 @@ let main _ = Error 3545, Line 8, Col 16, Line 8, Col 22, "The following required properties have to be initalized:" + Environment.NewLine + " property RAIO.GetSet: int with get, set" + Environment.NewLine + " property RAIO.GetInit: int with get, set" ] - #if !NETCOREAPP +#if !NETCOREAPP [] #else [] @@ -347,7 +347,7 @@ let main _ = Error 3545, Line 8, Col 16, Line 8, Col 30, "The following required properties have to be initalized:" + Environment.NewLine + " property RAIO.GetInit: int with get, set" ] - #if !NETCOREAPP +#if !NETCOREAPP [] #else [] @@ -378,4 +378,37 @@ let main _ = |> withLangVersionPreview |> withReferences [csharpLib] |> compileAndRun + |> shouldSucceed + +#if !NETCOREAPP + [] +#else + [] +#endif + let ``F# should produce a warning if RequiredMemberAttribute is specified`` () = + + let csharpLib = csharpRBaseClass + + let fsharpSource = + """ +open System +open RequiredAndInitOnlyProperties +open System.Runtime.CompilerServices + +type RAIOFS() = + [] + member val GetSet = 0 with get, set + +[] +let main _ = + + let raio = RAIOFS(GetSet=1) + + 0 +""" + FSharp fsharpSource + |> asExe + |> withLangVersionPreview + |> withReferences [csharpLib] + |> compile |> shouldSucceed \ No newline at end of file From 57848696007f66b7b37a9609a9fc4d8b466cf4c9 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Mon, 25 Jul 2022 17:22:22 +0200 Subject: [PATCH 12/18] Add setter check + add more unsupported attributes --- src/Compiler/Checking/infos.fs | 11 +++++++--- src/Compiler/TypedTree/TcGlobals.fs | 3 +++ .../Interop/RequiredAndInitOnlyProperties.fs | 20 ++++++------------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Compiler/Checking/infos.fs b/src/Compiler/Checking/infos.fs index 9876089ad76..45569425bac 100644 --- a/src/Compiler/Checking/infos.fs +++ b/src/Compiler/Checking/infos.fs @@ -1581,9 +1581,13 @@ type ILPropInfo = /// Indidcates whether IL property has an init-only setter (i.e. has the `System.Runtime.CompilerServices.IsExternalInit` modifer) member x.IsSetterInitOnly = - match x.SetterMethod.ILMethodRef.ReturnType with - | ILType.Modified(_, cls, _) -> cls.FullName = "System.Runtime.CompilerServices.IsExternalInit" - | _ -> false + assert x.HasSetter + if x.HasSetter then + match x.SetterMethod.ILMethodRef.ReturnType with + | ILType.Modified(_, cls, _) -> cls.FullName = "System.Runtime.CompilerServices.IsExternalInit" + | _ -> false + else + false /// Indicates if the IL property is static member x.IsStatic = (x.RawMetadata.CallingConv = ILThisConvention.Static) @@ -1598,6 +1602,7 @@ type ILPropInfo = (x.HasGetter && x.GetterMethod.IsNewSlot) || (x.HasSetter && x.SetterMethod.IsNewSlot) + /// Indicates if the property is required, i.e. has RequiredMemberAttribute applied. member x.IsRequired = TryFindILAttribute x.TcGlobals.attrib_RequiredMemberAttribute x.RawMetadata.CustomAttrs /// Get the names and types of the indexer arguments associated with the IL property. diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index 7eaf2ecbd18..31e0068d796 100755 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -983,6 +983,9 @@ type TcGlobals( tryFindSysAttrib "System.Runtime.CompilerServices.ModuleInitializerAttribute" tryFindSysAttrib "System.Runtime.CompilerServices.CallerArgumentExpressionAttribute" tryFindSysAttrib "System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute" + tryFindSysAttrib "System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute" + tryFindSysAttrib "System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute" + tryFindSysAttrib "System.Runtime.CompilerServices.RequiredMemberAttribute" ] |> List.choose (Option.map (fun x -> x.TyconRef)) override _.ToString() = "" diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs index ea7b40bcaaa..4dd7e754c41 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs @@ -386,29 +386,21 @@ let main _ = [] #endif let ``F# should produce a warning if RequiredMemberAttribute is specified`` () = - - let csharpLib = csharpRBaseClass - + // TODO: This test will start failing with different reason when we will move to .NET7, since RequiredMemberArgument will be in System.Runtime.*.dll. + // It will needs to be fixed then. let fsharpSource = """ +namespace FooBarBaz open System -open RequiredAndInitOnlyProperties open System.Runtime.CompilerServices type RAIOFS() = [] member val GetSet = 0 with get, set - -[] -let main _ = - - let raio = RAIOFS(GetSet=1) - - 0 """ FSharp fsharpSource - |> asExe + |> asLibrary |> withLangVersionPreview - |> withReferences [csharpLib] |> compile - |> shouldSucceed \ No newline at end of file + |> shouldFail + |> withErrorCode 39 \ No newline at end of file From cc928efd95ef9ee1ce0bf1f31102d6bd5c071c8c Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Mon, 25 Jul 2022 18:54:55 +0200 Subject: [PATCH 13/18] Fix prop pages --- .../PropertyPages/ApplicationPropPageBase.vb | 1 - 1 file changed, 1 deletion(-) diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/PropertyPages/ApplicationPropPageBase.vb b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/PropertyPages/ApplicationPropPageBase.vb index 1e5bb99afbd..98df251d91a 100644 --- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/PropertyPages/ApplicationPropPageBase.vb +++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/PropertyPages/ApplicationPropPageBase.vb @@ -4,7 +4,6 @@ Imports EnvDTE Imports Microsoft.VisualBasic Imports System -Imports System.IO Imports System.Collections Imports System.ComponentModel Imports System.Diagnostics From 0ef72fd79720769b5f63332cf34497be32a26862 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Thu, 28 Jul 2022 13:08:20 +0200 Subject: [PATCH 14/18] Update src/Compiler/Checking/CheckExpressions.fs Co-authored-by: Petr Pokorny --- src/Compiler/Checking/CheckExpressions.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 93cafc36e93..549a7beae7c 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -1505,7 +1505,7 @@ let CheckInitProperties (g: TcGlobals) (minfo: MethInfo) methodName mItem = let CheckRequiredProps (g:TcGlobals) (env: TcEnv) (cenv: TcFileState) (minfo: MethInfo) finalAssignedItemSetters mMethExpr = // Make sure, if apparent type has any required properties, they all are in the `finalAssignedItemSetters`. - // If if is a constructor, and it is not marked with `SetsRequiredMembersAttributeAttribute`, then: + // If it is a constructor, and it is not marked with `SetsRequiredMembersAttributeAttribute`, then: // 1. Get all properties of the type. // 2. Check if any of them has `IsRequired` set. // 2.1. If there are none, proceed as usual From 07762ca2cf513a943306b8bcec96021b7d72f796 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Thu, 28 Jul 2022 13:56:27 +0200 Subject: [PATCH 15/18] Addressed PR comments + added additional tests --- src/Compiler/Checking/CheckExpressions.fs | 1 + src/Compiler/Checking/infos.fs | 15 ++- .../Interop/RequiredAndInitOnlyProperties.fs | 92 +++++++++++++++++-- tests/FSharp.Test.Utilities/Compiler.fs | 5 + 4 files changed, 99 insertions(+), 14 deletions(-) diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 549a7beae7c..9bde95d14d5 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -9014,6 +9014,7 @@ and TcLookupThen cenv overallTy env tpenv mObjExpr objExpr objExprTy longId dela // To get better warnings we special case some of the few known mutate-a-struct method names let mutates = (if methodName = "MoveNext" || methodName = "GetNextArg" then DefinitelyMutates else PossiblyMutates) + // Check if we have properties with "init-only" setters, which we try to call after init is done. CheckInitProperties g (List.head minfos) methodName mItem #if !NO_TYPEPROVIDERS diff --git a/src/Compiler/Checking/infos.fs b/src/Compiler/Checking/infos.fs index 45569425bac..5e9af1a1103 100644 --- a/src/Compiler/Checking/infos.fs +++ b/src/Compiler/Checking/infos.fs @@ -154,6 +154,11 @@ let private GetInstantiationForPropertyVal g (ty, vref) = let memberParentTypars, memberMethodTypars, _retTy, parentTyArgs = AnalyzeTypeOfMemberVal false g (ty, vref) CombineMethInsts memberParentTypars memberMethodTypars parentTyArgs (generalizeTypars memberMethodTypars) +let private HasExternalInit (mref: ILMethodRef) : bool = + match mref.ReturnType with + | ILType.Modified(_, cls, _) -> cls.FullName = "System.Runtime.CompilerServices.IsExternalInit" + | _ -> false + /// Describes the sequence order of the introduction of an extension method. Extension methods that are introduced /// later through 'open' get priority in overload resolution. type ExtensionMethodPriority = uint64 @@ -938,10 +943,7 @@ type MethInfo = /// Indicates, wheter this method has `IsExternalInit` modreq. member x.HasExternalInit = match x with - | ILMeth (_, ilMethInfo, _) -> - match ilMethInfo.ILMethodRef.ReturnType with - | ILType.Modified(_, cls, _) -> cls.FullName = "System.Runtime.CompilerServices.IsExternalInit" - | _ -> false + | ILMeth (_, ilMethInfo, _) -> HasExternalInit ilMethInfo.ILMethodRef | _ -> false /// Indicates if this method is an extension member that is read-only. @@ -1581,11 +1583,8 @@ type ILPropInfo = /// Indidcates whether IL property has an init-only setter (i.e. has the `System.Runtime.CompilerServices.IsExternalInit` modifer) member x.IsSetterInitOnly = - assert x.HasSetter if x.HasSetter then - match x.SetterMethod.ILMethodRef.ReturnType with - | ILType.Modified(_, cls, _) -> cls.FullName = "System.Runtime.CompilerServices.IsExternalInit" - | _ -> false + HasExternalInit x.SetterMethod.ILMethodRef else false diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs index 4dd7e754c41..90ba1699311 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs @@ -8,12 +8,6 @@ open System module ``Required and init-only properties`` = - let withCSharpLanguageVersion (ver: CSharpLanguageVersion) (cUnit: CompilationUnit) : CompilationUnit = - match cUnit with - | CS cs -> CS { cs with LangVersion = ver } - | _ -> failwith "Only supported in C#" - - let csharpBaseClass = CSharp """ namespace RequiredAndInitOnlyProperties @@ -380,6 +374,92 @@ let main _ = |> compileAndRun |> shouldSucceed + #if !NETCOREAPP + [] + #else + [] + #endif + let ``F# should only be able to explicitly call constructors which set SetsRequiredMembersAttribute`` () = + + let csharpLib = + CSharp """ + // Until we move to .NET7 runtime (or use experimental) + namespace System.Runtime.CompilerServices + { + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] + public sealed class RequiredMemberAttribute : Attribute { } + [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] + public sealed class CompilerFeatureRequiredAttribute : Attribute + { + public CompilerFeatureRequiredAttribute(string featureName) + { + FeatureName = featureName; + } + public string FeatureName { get; } + public bool IsOptional { get; init; } + public const string RefStructs = nameof(RefStructs); + public const string RequiredMembers = nameof(RequiredMembers); + } + } + + namespace System.Diagnostics.CodeAnalysis + { + [AttributeUsage(AttributeTargets.Constructor, AllowMultiple=false, Inherited=false)] + public sealed class SetsRequiredMembersAttribute : Attribute {} + } + + namespace RequiredAndInitOnlyProperties + { + using System.Runtime.CompilerServices; + using System.Diagnostics.CodeAnalysis; + + public sealed class RAIO + { + public required int GetSet { get; set; } + public required int GetInit { get; init; } + [SetsRequiredMembers] + public RAIO(int foo) {} // Should be legal to call any constructor which does have "SetsRequiredMembersAttribute" + public RAIO(int foo, int bar) {} // Should be illegal to call any constructor which does not have "SetsRequiredMembersAttribute" + } + + }""" |> withCSharpLanguageVersion CSharpLanguageVersion.Preview |> withName "csLib" + + let fsharpSource = + """ + open System + open RequiredAndInitOnlyProperties + + [] + let main _ = + let _raio = RAIO(1) + 0 + """ + FSharp fsharpSource + |> asExe + |> withLangVersionPreview + |> withReferences [csharpLib] + |> compileAndRun + |> shouldSucceed + |> ignore + + let fsharpSource2 = + """ + open System + open RequiredAndInitOnlyProperties + + [] + let main _ = + let _raio = RAIO(1,2) + 0 + """ + FSharp fsharpSource2 + |> asExe + |> withLangVersionPreview + |> withReferences [csharpLib] + |> compile + |> shouldFail + |> withSingleDiagnostic (Error 3545, Line 7, Col 21, Line 7, Col 30, "The following required properties have to be initalized:" + Environment.NewLine + " property RAIO.GetSet: int with get, set" + Environment.NewLine + " property RAIO.GetInit: int with get, set") + #if !NETCOREAPP [] #else diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 54822b93d80..574d7dae1ee 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -452,6 +452,11 @@ module rec Compiler = let withRefOut (name:string) (cUnit: CompilationUnit) : CompilationUnit = withOptionsHelper [ $"--refout:{name}" ] "withNoInterfaceData is only supported for F#" cUnit + let withCSharpLanguageVersion (ver: CSharpLanguageVersion) (cUnit: CompilationUnit) : CompilationUnit = + match cUnit with + | CS cs -> CS { cs with LangVersion = ver } + | _ -> failwith "Only supported in C#" + let asLibrary (cUnit: CompilationUnit) : CompilationUnit = match cUnit with | FS fs -> FS { fs with OutputType = CompileOutput.Library } From 3bc625b19452fc9618ea2e8001efe9ec023d0754 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Thu, 28 Jul 2022 15:39:37 +0200 Subject: [PATCH 16/18] Update src/Compiler/Checking/infos.fs Co-authored-by: Petr Pokorny --- src/Compiler/Checking/infos.fs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Compiler/Checking/infos.fs b/src/Compiler/Checking/infos.fs index 5e9af1a1103..ddaf2e35b0c 100644 --- a/src/Compiler/Checking/infos.fs +++ b/src/Compiler/Checking/infos.fs @@ -1583,10 +1583,7 @@ type ILPropInfo = /// Indidcates whether IL property has an init-only setter (i.e. has the `System.Runtime.CompilerServices.IsExternalInit` modifer) member x.IsSetterInitOnly = - if x.HasSetter then - HasExternalInit x.SetterMethod.ILMethodRef - else - false + x.HasSetter && HasExternalInit x.SetterMethod.ILMethodRef /// Indicates if the IL property is static member x.IsStatic = (x.RawMetadata.CallingConv = ILThisConvention.Static) From 66407b2e4f9502b84849467d58660a85bd81d05c Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Thu, 28 Jul 2022 19:06:56 +0200 Subject: [PATCH 17/18] Moved condition outside of list expression --- src/Compiler/Checking/CheckExpressions.fs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 9bde95d14d5..268847381f3 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -1511,21 +1511,23 @@ let CheckRequiredProps (g:TcGlobals) (env: TcEnv) (cenv: TcFileState) (minfo: Me // 2.1. If there are none, proceed as usual // 2.2. If there are any, make sure all of them (or their setters) are in `finalAssignedItemSetters`. // 3. If some are missing, produce a diagnostic which missing ones. - if g.langVersion.SupportsFeature(LanguageFeature.RequiredPropertiesSupport) && minfo.IsConstructor then + if g.langVersion.SupportsFeature(LanguageFeature.RequiredPropertiesSupport) + && minfo.IsConstructor + && not (TryFindILAttribute g.attrib_SetsRequiredMembersAttribute (minfo.GetCustomAttrs())) then + let requiredProps = [ - if not (TryFindILAttribute g.attrib_SetsRequiredMembersAttribute (minfo.GetCustomAttrs())) then - let props = GetImmediateIntrinsicPropInfosOfType (None, AccessibleFromSomeFSharpCode) g cenv.amap range0 minfo.ApparentEnclosingType - for prop in props do - if prop.IsRequired then - prop + let props = GetImmediateIntrinsicPropInfosOfType (None, AccessibleFromSomeFSharpCode) g cenv.amap range0 minfo.ApparentEnclosingType + for prop in props do + if prop.IsRequired then + prop ] - + if requiredProps.Length > 0 then - let setterPropNames = + let setterPropNames = finalAssignedItemSetters |> List.choose (function | AssignedItemSetter(_, AssignedPropSetter (pinfo, _, _), _) -> Some pinfo.PropertyName | _ -> None) - + let missingProps = requiredProps |> List.filter (fun pinfo -> not (List.contains pinfo.PropertyName setterPropNames)) From 764c158cd90dc2719bf01d40a0a3ae1ca531f5b2 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Thu, 28 Jul 2022 20:14:25 +0200 Subject: [PATCH 18/18] PR fixes --- src/Compiler/AbstractIL/il.fs | 2 +- src/Compiler/Checking/CheckExpressions.fs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Compiler/AbstractIL/il.fs b/src/Compiler/AbstractIL/il.fs index aa06532ce1c..23e6186253a 100644 --- a/src/Compiler/AbstractIL/il.fs +++ b/src/Compiler/AbstractIL/il.fs @@ -1207,7 +1207,7 @@ type ILAttributes(array: ILAttribute[]) = member _.AsList() = array |> Array.toList - static member internal Empty = ILAttributes([||]) + static member val internal Empty = ILAttributes([||]) [] type ILAttributesStored = diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 268847381f3..fe124187b64 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -1503,7 +1503,7 @@ let CheckInitProperties (g: TcGlobals) (minfo: MethInfo) methodName mItem = if minfo.HasExternalInit then errorR (Error (FSComp.SR.tcSetterForInitOnlyPropertyCannotBeCalled1 methodName, mItem)) -let CheckRequiredProps (g:TcGlobals) (env: TcEnv) (cenv: TcFileState) (minfo: MethInfo) finalAssignedItemSetters mMethExpr = +let CheckRequiredProperties (g:TcGlobals) (env: TcEnv) (cenv: TcFileState) (minfo: MethInfo) finalAssignedItemSetters mMethExpr = // Make sure, if apparent type has any required properties, they all are in the `finalAssignedItemSetters`. // If it is a constructor, and it is not marked with `SetsRequiredMembersAttributeAttribute`, then: // 1. Get all properties of the type. @@ -9773,8 +9773,8 @@ and TcMethodApplication let setterExprPrebinders, callExpr3 = let expr = callExpr2b - CheckRequiredProps g env cenv finalCalledMethInfo finalAssignedItemSetters mMethExpr - + CheckRequiredProperties g env cenv finalCalledMethInfo finalAssignedItemSetters mMethExpr + if isCheckingAttributeCall then [], expr elif isNil finalAssignedItemSetters then