From 2c9749ad8f7ce45e8bd03b6253ba80da58299f2e Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 15 Apr 2026 12:12:08 +0200 Subject: [PATCH] Fix #12796: handle arrays of user-defined types in custom attributes Empty arrays of non-encodable types (classes, records, structs) in custom attributes now compile successfully by encoding them as System.Object[] per ECMA-335. Non-empty arrays of such types produce FS3885 instead of the internal error FS0192. Changes: - IlxGen.fs: detect unencodable element types in array attribute args - il.fs: add 0x51 (SERIALIZATION_TYPE_TAGGED_OBJECT) decoder - FSComp.txt: new diagnostic FS3885 - Tests: 7 new AttributeCheckingTests (compile + ILVerify + run) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../.FSharp.Compiler.Service/11.0.100.md | 1 + src/Compiler/AbstractIL/il.fs | 1 + src/Compiler/CodeGen/IlxGen.fs | 37 +++- src/Compiler/FSComp.txt | 1 + src/Compiler/xlf/FSComp.txt.cs.xlf | 9 +- src/Compiler/xlf/FSComp.txt.de.xlf | 9 +- src/Compiler/xlf/FSComp.txt.es.xlf | 9 +- src/Compiler/xlf/FSComp.txt.fr.xlf | 9 +- src/Compiler/xlf/FSComp.txt.it.xlf | 9 +- src/Compiler/xlf/FSComp.txt.ja.xlf | 9 +- src/Compiler/xlf/FSComp.txt.ko.xlf | 9 +- src/Compiler/xlf/FSComp.txt.pl.xlf | 9 +- src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 9 +- src/Compiler/xlf/FSComp.txt.ru.xlf | 9 +- src/Compiler/xlf/FSComp.txt.tr.xlf | 9 +- src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 9 +- src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 9 +- .../Language/AttributeCheckingTests.fs | 208 ++++++++++++++++++ 18 files changed, 337 insertions(+), 28 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index 8669e7142f..6063df9519 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -27,6 +27,7 @@ * Fix box instruction for literal upcasts. (Issue [#18319](https://github.com/dotnet/fsharp/issues/18319), [PR #19338](https://github.com/dotnet/fsharp/pull/19338)) * Fix Decimal Literal causes InvalidProgramException in Debug builds. (Issue [#18956](https://github.com/dotnet/fsharp/issues/18956), [PR #19338](https://github.com/dotnet/fsharp/pull/19338)) * Fix `AttributeUsage.AllowMultiple` not being inherited for attributes subclassed in C#. ([Issue #17107](https://github.com/dotnet/fsharp/issues/17107), [PR #19315](https://github.com/dotnet/fsharp/pull/19315)) +* Fix internal error `FS0192: encodeCustomAttrElemType` when using arrays of user-defined types as custom attribute arguments. Empty arrays (e.g. `[]`) now compile successfully; non-empty arrays of unencodable types report a proper diagnostic (FS3885) instead of an internal error. ([Issue #12796](https://github.com/dotnet/fsharp/issues/12796), [PR #19472](https://github.com/dotnet/fsharp/pull/19472)) ### Added diff --git a/src/Compiler/AbstractIL/il.fs b/src/Compiler/AbstractIL/il.fs index 8e836ef548..5a80b12fbd 100644 --- a/src/Compiler/AbstractIL/il.fs +++ b/src/Compiler/AbstractIL/il.fs @@ -4978,6 +4978,7 @@ let rec decodeCustomAttrElemType bytes sigptr x = let elemTy, sigptr = decodeCustomAttrElemType bytes sigptr et mkILArr1DTy elemTy, sigptr | x when x = 0x50uy -> PrimaryAssemblyILGlobals.typ_Type, sigptr + | x when x = 0x51uy -> PrimaryAssemblyILGlobals.typ_Object, sigptr // SERIALIZATION_TYPE_TAGGED_OBJECT (ECMA-335 II.23.3) | _ -> failwithf "decodeCustomAttrElemType ilg: unrecognized custom element type: %A" x /// Given a custom attribute element, encode it to a binary representation according to the rules in Ecma 335 Partition II. diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index b76cc30293..64a1d717ba 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -10294,7 +10294,7 @@ and EmitRestoreStack cgbuf (savedStack, savedStackLocals) = //GenAttr: custom attribute generation //------------------------------------------------------------------------- -and GenAttribArg amap g eenv x (ilArgTy: ILType) = +and GenAttribArg amap (g: TcGlobals) eenv x (ilArgTy: ILType) = match stripDebugPoints x, ilArgTy with // Detect 'null' used for an array argument @@ -10334,7 +10334,40 @@ and GenAttribArg amap g eenv x (ilArgTy: ILType) = // Detect '[| ... |]' nodes | Expr.Op(TOp.Array, [ elemTy ], args, m), _ -> let ilElemTy = GenType amap m eenv.tyenv elemTy - ILAttribElem.Array(ilElemTy, List.map (fun arg -> GenAttribArg amap g eenv arg ilElemTy) args) + + // Check if element type can be encoded in custom attribute metadata (ECMA-335 II.23.3). + // Valid element types: primitives, enums, string, System.Type, System.Object. + let isEncodableElemType = + match ilElemTy with + | ILType.Value tspec -> + match tspec.Name with + | "System.SByte" + | "System.Byte" + | "System.Int16" + | "System.UInt16" + | "System.Int32" + | "System.UInt32" + | "System.Int64" + | "System.UInt64" + | "System.Double" + | "System.Single" + | "System.Char" + | "System.Boolean" -> true + | _ -> isEnumTy g elemTy + | ILType.Boxed tspec -> + tspec.Name = "System.String" + || tspec.Name = "System.Object" + || tspec.Name = "System.Type" + | _ -> false + + if not isEncodableElemType then + if args.IsEmpty then + // Empty arrays: substitute System.Object as element type since no elements need encoding. + ILAttribElem.Array(g.ilg.typ_Object, []) + else + error (Error(FSComp.SR.ilCustomAttrInvalidArrayElemType (ilElemTy.TypeRef.Name), m)) + else + ILAttribElem.Array(ilElemTy, List.map (fun arg -> GenAttribArg amap g eenv arg ilElemTy) args) // Detect 'typeof' calls | TypeOfExpr g ty, _ -> ILAttribElem.Type(Some(GenType amap x.Range eenv.tyenv ty)) diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index a4007147b9..83c10419f8 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1814,3 +1814,4 @@ featurePreprocessorElif,"#elif preprocessor directive" 3882,lexHashElifMustBeFirst,"#elif directive must appear as the first non-whitespace character on a line" 3883,lexHashElifMustHaveIdent,"#elif directive should be immediately followed by an identifier" 3884,tcFunctionValueUsedAsInterpolatedStringArg,"This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments." +3885,ilCustomAttrInvalidArrayElemType,"The type '%s' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object." diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 6896c33a6a..1f91a5bf62 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -787,6 +787,11 @@ Výraz if musí vrátit řazenou kolekci členů o délce {0} typu\n {1} \nto splňovat požadavky na typ kontextu. Aktuálně vrací řazenou kolekci členů o délce {2} typu\n {3} \n + + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + + Unknown debug point '{0}'. The available debug points are '{1}'. Neznámý bod ladění {0}. Dostupné body ladění jsou {1}. @@ -8952,12 +8957,12 @@ Rozšíření správce závislostí {0} nešlo načíst. Zpráva: {1} - + Warn when a function value is used as an interpolated string argument Warn when a function value is used as an interpolated string argument - + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 3966a59a85..35e978e271 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -787,6 +787,11 @@ Der „if“-Ausdruck muss ein Tupel mit der Länge {0} vom Typ\n {1} \nzurückgeben, um die Kontexttypanforderungen zu erfüllen. Derzeit wird ein Tupel mit der Länge {2} vom Typ\n {3} \nzurückgegeben. + + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + + Unknown debug point '{0}'. The available debug points are '{1}'. Unbekannter Debugpunkt „{0}“. Die verfügbaren Debugpunkte sind „{1}“. @@ -8952,12 +8957,12 @@ Die Abhängigkeits-Manager-Erweiterung "{0}" konnte nicht geladen werden. Meldung: {1} - + Warn when a function value is used as an interpolated string argument Warn when a function value is used as an interpolated string argument - + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 08828606dd..6ab68dbb4c 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -787,6 +787,11 @@ La expresión "if" debe devolver una tupla de longitud {0} de tipo\n {1} \npara satisfacer los requisitos de tipo de contexto. Actualmente devuelve una tupla de longitud {2} de tipo\n {3} \n + + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + + Unknown debug point '{0}'. The available debug points are '{1}'. Punto de depuración desconocido \"{0}\". Los puntos de depuración disponibles son \"{1}\". @@ -8952,12 +8957,12 @@ No se pudo cargar la extensión del administrador de dependencias {0}. Mensaje: {1} - + Warn when a function value is used as an interpolated string argument Warn when a function value is used as an interpolated string argument - + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 5a28ec1595..6f7290b88b 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -787,6 +787,11 @@ L’expression « if » doit retourner un tuple de longueur {0} de type\n {1} \npour répondre aux exigences de type de contexte. Il retourne actuellement un tuple de longueur {2} de type\n {3} \n + + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + + Unknown debug point '{0}'. The available debug points are '{1}'. Point de débogage inconnu « {0} ». Les points de débogage disponibles sont «{1}». @@ -8952,12 +8957,12 @@ Impossible de charger l'extension du gestionnaire de dépendances {0}. Message : {1} - + Warn when a function value is used as an interpolated string argument Warn when a function value is used as an interpolated string argument - + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 5dead052c6..0c4ee13ed5 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -787,6 +787,11 @@ L'espressione 'if' deve restituire una tupla di lunghezza {0} di tipo\n {1} \nper soddisfare i requisiti del tipo di contesto. Restituisce attualmente una tupla di lunghezza {2} di tipo\n {3} \n + + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + + Unknown debug point '{0}'. The available debug points are '{1}'. Punto di debug '{0}' sconosciuto. I punti di debug disponibili sono '{1}'. @@ -8952,12 +8957,12 @@ Non è stato possibile caricare l'estensione {0} di gestione delle dipendenze. Messaggio: {1} - + Warn when a function value is used as an interpolated string argument Warn when a function value is used as an interpolated string argument - + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index f491fb0c4c..4d787f0a61 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -787,6 +787,11 @@ 'if' 式は、コンテキスト型の要件を満たすために、\n {1} \n 型の長さの {0} のタプルを返す必要があります。現在、型の {2} 長さのタプルを返します\n {3} \n + + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + + Unknown debug point '{0}'. The available debug points are '{1}'. 不明なデバッグ ポイントの `{0}`。使用可能なデバッグ ポイントは `{1}` です。 @@ -8952,12 +8957,12 @@ 依存関係マネージャーの拡張機能 {0} を読み込むことができませんでした。メッセージ: {1} - + Warn when a function value is used as an interpolated string argument Warn when a function value is used as an interpolated string argument - + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index f8185fb2a2..d19c836af8 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -787,6 +787,11 @@ 'if' 식은 컨텍스트 유형 요구 사항을 충족하기 위해 형식이\n {1} \n이고 길이가 {0}인 튜플을 반환해야 합니다. 해당 식은 현재 형식이 {3}이고 길이가\n {2}인 튜플을 반환합니다. \n + + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + + Unknown debug point '{0}'. The available debug points are '{1}'. 알 수 없는 디버그 지점 '{0}'. 사용 가능한 디버그 지점은 '{1}'입니다. @@ -8952,12 +8957,12 @@ 종속성 관리자 확장 {0}을(를) 로드할 수 없습니다. 메시지: {1} - + Warn when a function value is used as an interpolated string argument Warn when a function value is used as an interpolated string argument - + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 7e81e135ee..3e5a276a2d 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -787,6 +787,11 @@ Wyrażenie „if” musi zwrócić krotkę o długości {0} typu\n {1} \naby spełnić wymagania dotyczące typu kontekstu. Obecnie zwraca krotkę o długości {2} typu\n {3} \n + + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + + Unknown debug point '{0}'. The available debug points are '{1}'. Nieznany punkt debugowania „{0}”. Dostępnymi punktami debugowania są „{1}”. @@ -8952,12 +8957,12 @@ Nie można załadować rozszerzenia menedżera zależności {0}. Komunikat: {1} - + Warn when a function value is used as an interpolated string argument Warn when a function value is used as an interpolated string argument - + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 22a5db4504..d303e38c02 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -787,6 +787,11 @@ Se a expressão 'if' precisa retornar uma tupla de comprimento {0} do tipo\n {1} \npara atender aos requisitos de tipo de contexto. Atualmente, ele retorna uma tupla de comprimento {2} do tipo\n {3} \n + + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + + Unknown debug point '{0}'. The available debug points are '{1}'. Ponto de depuração desconhecido '{0}'. Os pontos de depuração disponíveis são '{1}'. @@ -8952,12 +8957,12 @@ Não foi possível carregar a extensão do gerenciador de dependências {0}. Mensagem: {1} - + Warn when a function value is used as an interpolated string argument Warn when a function value is used as an interpolated string argument - + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 8f5220ba47..540509cfe6 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -787,6 +787,11 @@ Выражение "if" должно возвращать кортеж длиной {0} типа\n {1} \nдля соответствия требованиям к типу контекста. В настоящее время возвращается кортеж длиной {2} типа\n {3} \n + + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + + Unknown debug point '{0}'. The available debug points are '{1}'. Неизвестная точка отладки \"{0}\". Доступные точки отладки: \"{1}\". @@ -8952,12 +8957,12 @@ Не удалось загрузить расширение диспетчера зависимостей {0}. Сообщение: {1} - + Warn when a function value is used as an interpolated string argument Warn when a function value is used as an interpolated string argument - + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 1750982712..efe13f8cbb 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -787,6 +787,11 @@ Bağlam türü gereksinimlerini karşılaması için 'if' ifadesinin {0} uzunluğunda türü\n {1} \nolan bir demet döndürmesi gerekiyor. Şu anda {2} uzunluğunda türü\n {3} \nolan bir demet döndürüyor + + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + + Unknown debug point '{0}'. The available debug points are '{1}'. Bilinmeyen hata ayıklama noktası '{0}'. Kullanılabilir hata ayıklama noktaları '{1}'. @@ -8952,12 +8957,12 @@ {0} bağımlılık yöneticisi uzantısı yüklenemedi. İleti: {1} - + Warn when a function value is used as an interpolated string argument Warn when a function value is used as an interpolated string argument - + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index bf26625f8e..e6219c709d 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -787,6 +787,11 @@ “if” 表达式需要返回长度为 {0} 的类型的元组\n {1} \n以满足上下文类型要求。它当前返回了长度为 {2} 的类型的元组\n {3} \n + + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + + Unknown debug point '{0}'. The available debug points are '{1}'. 调试点“{0}”未知。可用的调试点为“{1}”。 @@ -8952,12 +8957,12 @@ 无法加载依赖项管理器扩展 {0}。消息: {1} - + Warn when a function value is used as an interpolated string argument Warn when a function value is used as an interpolated string argument - + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 2a63e5ad75..372bdee241 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -787,6 +787,11 @@ 'if' 運算式必須傳回類型為\n {1} \n的元組長度{0},才能滿足內容類型需求。目前傳回的是類型為\n {3} \n的元組長度 {2} + + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + The type '{0}' is not a valid custom attribute argument type. Custom attribute arrays must have elements of primitive types, enums, string, System.Type, or System.Object. + + Unknown debug point '{0}'. The available debug points are '{1}'. 未知的偵錯點 '{0}'。可用的偵錯點為 '{1}'。 @@ -8952,12 +8957,12 @@ 無法載入相依性管理員延伸模組 {0}。訊息: {1} - + Warn when a function value is used as an interpolated string argument Warn when a function value is used as an interpolated string argument - + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. diff --git a/tests/FSharp.Compiler.ComponentTests/Language/AttributeCheckingTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/AttributeCheckingTests.fs index 898706bca5..c776d56e35 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/AttributeCheckingTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/AttributeCheckingTests.fs @@ -3,6 +3,7 @@ namespace Language open Xunit +open FSharp.Test open FSharp.Test.Compiler module AttributeCheckingTests = @@ -188,3 +189,210 @@ type C() = class end |> withReferences [csharpLib] |> compile |> shouldSucceed + + // https://github.com/dotnet/fsharp/issues/12796 + // Empty arrays of user-defined class types in custom attributes should compile successfully. + // Previously this caused FS0192 internal error in encodeCustomAttrElemType. + [] + let ``Issue 12796 - Empty array of class type in attribute compiles, verifies IL, and runs`` () = + FSharp + """ +module TestModule + +open System +open System.ComponentModel +open System.Reflection + +[] +type A() = class end + +[] +type B() = class end + +[] +let main _ = + let attr = typeof.GetCustomAttribute() + let arr = attr.Value :?> obj[] + if arr.Length <> 0 then failwith "Expected empty array" + printfn "class: len=%d" arr.Length + 0 + """ + |> asExe + |> compile + |> shouldSucceed + |> verifyPEFileWithSystemDlls + |> shouldSucceed + |> run + |> shouldSucceed + |> withStdOutContains "class: len=0" + + // https://github.com/dotnet/fsharp/issues/12796 + [] + let ``Issue 12796 - Empty array of record type in attribute compiles, verifies IL, and runs`` () = + FSharp + """ +module TestModule + +open System +open System.ComponentModel +open System.Reflection + +type A = { AField: string } + +[] +type B() = class end + +[] +let main _ = + let attr = typeof.GetCustomAttribute() + let arr = attr.Value :?> obj[] + if arr.Length <> 0 then failwith "Expected empty array" + printfn "record: len=%d" arr.Length + 0 + """ + |> asExe + |> compile + |> shouldSucceed + |> verifyPEFileWithSystemDlls + |> shouldSucceed + |> run + |> shouldSucceed + |> withStdOutContains "record: len=0" + + // https://github.com/dotnet/fsharp/issues/12796 + [] + let ``Issue 12796 - Empty array of enum type in attribute compiles, verifies IL, and runs`` () = + FSharp + """ +module TestModule + +open System +open System.ComponentModel +open System.Reflection + +type MyEnum = A = 0 | B = 1 + +[] +type T() = class end + +[] +let main _ = + let attr = typeof.GetCustomAttribute() + let arr = attr.Value :?> MyEnum[] + if arr.Length <> 0 then failwith "Expected empty array" + printfn "enum: len=%d" arr.Length + 0 + """ + |> asExe + |> compile + |> shouldSucceed + |> verifyPEFileWithSystemDlls + |> shouldSucceed + |> run + |> shouldSucceed + |> withStdOutContains "enum: len=0" + + // https://github.com/dotnet/fsharp/issues/12796 + [] + let ``Issue 12796 - Empty array of primitive type in attribute compiles, verifies IL, and runs`` () = + FSharp + """ +module TestModule + +open System +open System.ComponentModel +open System.Reflection + +[] +type T() = class end + +[] +let main _ = + let attr = typeof.GetCustomAttribute() + let arr = attr.Value :?> int[] + if arr.Length <> 0 then failwith "Expected empty array" + printfn "int: len=%d" arr.Length + 0 + """ + |> asExe + |> compile + |> shouldSucceed + |> verifyPEFileWithSystemDlls + |> shouldSucceed + |> run + |> shouldSucceed + |> withStdOutContains "int: len=0" + + // https://github.com/dotnet/fsharp/issues/12796 + // Non-empty arrays of user-defined types should produce FS3885 diagnostic instead of FS0192 internal error. + [] + let ``Issue 12796 - Non-empty array of user-defined type in attribute gives proper error`` () = + FSharp + """ +module TestModule + +open System.ComponentModel + +[] +type A() = class end + +[] +type B() = class end + """ + |> compile + |> shouldFail + |> withErrorCode 3885 + |> withDiagnosticMessageMatches "not a valid custom attribute argument type" + + // https://github.com/dotnet/fsharp/issues/12796 + [] + let ``Issue 12796 - Non-empty array of struct type in attribute gives proper error`` () = + FSharp + """ +module TestModule + +open System.ComponentModel + +[] +type MyStruct = { X: int } + +[] +type B() = class end + """ + |> compile + |> shouldFail + |> withErrorCode 267 + + // https://github.com/dotnet/fsharp/issues/12796 + [] + let ``Issue 12796 - Empty array of struct type in attribute compiles, verifies IL, and runs`` () = + FSharp + """ +module TestModule + +open System +open System.ComponentModel +open System.Reflection + +[] +type MyStruct = { X: int; Y: int } + +[] +type T() = class end + +[] +let main _ = + let attr = typeof.GetCustomAttribute() + let arr = attr.Value :?> obj[] + if arr.Length <> 0 then failwith "Expected empty array" + printfn "struct: len=%d" arr.Length + 0 + """ + |> asExe + |> compile + |> shouldSucceed + |> verifyPEFileWithSystemDlls + |> shouldSucceed + |> run + |> shouldSucceed + |> withStdOutContains "struct: len=0"