From ce4c244e9ba2130b094730edcafed5dbae11a388 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 13 Apr 2026 12:15:39 +0200 Subject: [PATCH 1/4] Fix #12796: proper diagnostic for invalid custom attribute array element types Previously, using an array of a user-defined type as a custom attribute argument (e.g. []) caused an internal error FS0192 in encodeCustomAttrElemType. The ECMA 335 metadata format requires the array element type to be encoded even for empty arrays, and only primitive types, enums, string, System.Type, and System.Object are valid. This change adds a validation check in GenAttribArg (IlxGen.fs) that detects unsupported element types before reaching the IL writer, and reports a proper diagnostic (FS3885) instead of crashing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../.FSharp.Compiler.Service/11.0.100.md | 1 + src/Compiler/CodeGen/IlxGen.fs | 12 ++++++++++++ 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 | 19 +++++++++++++++++++ 17 files changed, 124 insertions(+), 26 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 d2d59c319a1..0180a8a6e81 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -19,6 +19,7 @@ * Fixed how the source ranges of warn directives are reported (as trivia) in the parser output (by not reporting leading spaces). ([Issue #19405](https://github.com/dotnet/fsharp/issues/19405), [PR #19408]((https://github.com/dotnet/fsharp/pull/19408))) * Fix UoM value type `ToString()` returning garbage values when `--checknulls+` is enabled, caused by double address-taking in codegen. ([Issue #19435](https://github.com/dotnet/fsharp/issues/19435), [PR #19440](https://github.com/dotnet/fsharp/pull/19440)) * Fix completion inconsistently showing some obsolete members (fields and events) while hiding others (methods and properties). All obsolete members are now consistently hidden by default. ([Issue #13512](https://github.com/dotnet/fsharp/issues/13512), [PR #19506](https://github.com/dotnet/fsharp/pull/19506)) +* Fix internal error `FS0192: encodeCustomAttrElemType` when using an array of user-defined type as a custom attribute argument. Now reports a proper diagnostic (FS3885). ([Issue #12796](https://github.com/dotnet/fsharp/issues/12796), [PR #19472](https://github.com/dotnet/fsharp/pull/19472)) ### Added diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index 6dcb2f92ee8..86747c52373 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -10222,6 +10222,18 @@ 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 + + // Validate element type is encodable in custom attribute metadata (ECMA 335). + // Only primitive types, enums, string, System.Type, and System.Object are valid. + match ilElemTy with + | ILType.Boxed tspec when + tspec.Name <> "System.String" + && tspec.Name <> "System.Object" + && tspec.Name <> "System.Type" + -> + error (Error(FSComp.SR.ilCustomAttrInvalidArrayElemType (tspec.Name), m)) + | _ -> () + ILAttribElem.Array(ilElemTy, List.map (fun arg -> GenAttribArg amap g eenv arg ilElemTy) args) // Detect 'typeof' calls diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index a4007147b9a..83c10419f89 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 6896c33a6a4..1f91a5bf626 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 3966a59a853..35e978e2710 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 08828606dd6..6ab68dbb4c2 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 5a28ec15953..6f7290b88b1 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 5dead052c6a..0c4ee13ed5c 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 f491fb0c4c5..4d787f0a61b 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 f8185fb2a22..d19c836af8c 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 7e81e135eeb..3e5a276a2db 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 22a5db4504c..d303e38c020 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 8f5220ba47e..540509cfe6a 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 17509827124..efe13f8cbb4 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 bf26625f8ec..e6219c709de 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 2a63e5ad753..372bdee241c 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 d91997b68f0..ca1fedac4b0 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/AttributeCheckingTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/AttributeCheckingTests.fs @@ -77,3 +77,22 @@ type C() = |> withReferences [csharpBaseClass] |> compile |> shouldSucceed + + // https://github.com/dotnet/fsharp/issues/12796 + // Passing an array of a user-defined type as a custom attribute argument is invalid per ECMA 335. + // Previously this caused FS0192 internal error in encodeCustomAttrElemType. Now it gives a proper diagnostic. + [] + let ``Issue 12796 - DefaultValue empty array on record field of array type should not cause internal error`` () = + FSharp + """ +module TestModule + +open System.ComponentModel + +type A = { AField: string } +type B = { [] BField: A[] } + """ + |> asLibrary + |> compile + |> shouldFail + |> withErrorCode 3885 From 26e4d83e11f2f55218e73f91b822a44f439ed489 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 14 Apr 2026 00:20:19 +0200 Subject: [PATCH 2/4] Fix empty array handling in custom attributes: use Object element type instead of erroring Empty arrays of user-defined types in custom attributes (e.g. []) no longer produce FS3885. Since no elements need encoding, System.Object is used as the element type. Non-empty arrays of unencodable types still error correctly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../.FSharp.Compiler.Service/11.0.100.md | 2 +- src/Compiler/CodeGen/IlxGen.fs | 30 ++++++++++++------- .../Language/AttributeCheckingTests.fs | 8 ++--- 3 files changed, 24 insertions(+), 16 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 0180a8a6e81..528c1c61487 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -19,7 +19,7 @@ * Fixed how the source ranges of warn directives are reported (as trivia) in the parser output (by not reporting leading spaces). ([Issue #19405](https://github.com/dotnet/fsharp/issues/19405), [PR #19408]((https://github.com/dotnet/fsharp/pull/19408))) * Fix UoM value type `ToString()` returning garbage values when `--checknulls+` is enabled, caused by double address-taking in codegen. ([Issue #19435](https://github.com/dotnet/fsharp/issues/19435), [PR #19440](https://github.com/dotnet/fsharp/pull/19440)) * Fix completion inconsistently showing some obsolete members (fields and events) while hiding others (methods and properties). All obsolete members are now consistently hidden by default. ([Issue #13512](https://github.com/dotnet/fsharp/issues/13512), [PR #19506](https://github.com/dotnet/fsharp/pull/19506)) -* Fix internal error `FS0192: encodeCustomAttrElemType` when using an array of user-defined type as a custom attribute argument. Now reports a proper diagnostic (FS3885). ([Issue #12796](https://github.com/dotnet/fsharp/issues/12796), [PR #19472](https://github.com/dotnet/fsharp/pull/19472)) +* Fix internal error `FS0192: encodeCustomAttrElemType` when using an empty array of user-defined type as a custom attribute argument (e.g. `[]`). Empty arrays of arbitrary types are now encoded using `System.Object` as the element type. ([Issue #12796](https://github.com/dotnet/fsharp/issues/12796), [PR #19472](https://github.com/dotnet/fsharp/pull/19472)) ### Added diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index 86747c52373..bf54687e09b 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -10223,18 +10223,26 @@ and GenAttribArg amap g eenv x (ilArgTy: ILType) = | Expr.Op(TOp.Array, [ elemTy ], args, m), _ -> let ilElemTy = GenType amap m eenv.tyenv elemTy - // Validate element type is encodable in custom attribute metadata (ECMA 335). - // Only primitive types, enums, string, System.Type, and System.Object are valid. - match ilElemTy with - | ILType.Boxed tspec when - tspec.Name <> "System.String" - && tspec.Name <> "System.Object" - && tspec.Name <> "System.Type" - -> - error (Error(FSComp.SR.ilCustomAttrInvalidArrayElemType (tspec.Name), m)) - | _ -> () + // Check if element type can be encoded in custom attribute metadata (ECMA 335). + // Valid element types: primitives, enums, string, System.Type, System.Object. + let isUnencodableBoxedElemType = + match ilElemTy with + | ILType.Boxed tspec when + tspec.Name <> "System.String" + && tspec.Name <> "System.Object" + && tspec.Name <> "System.Type" + -> + true + | _ -> false - ILAttribElem.Array(ilElemTy, List.map (fun arg -> GenAttribArg amap g eenv arg ilElemTy) args) + if isUnencodableBoxedElemType 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/tests/FSharp.Compiler.ComponentTests/Language/AttributeCheckingTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/AttributeCheckingTests.fs index ca1fedac4b0..d50401ed2ef 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/AttributeCheckingTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/AttributeCheckingTests.fs @@ -79,8 +79,9 @@ type C() = |> shouldSucceed // https://github.com/dotnet/fsharp/issues/12796 - // Passing an array of a user-defined type as a custom attribute argument is invalid per ECMA 335. - // Previously this caused FS0192 internal error in encodeCustomAttrElemType. Now it gives a proper diagnostic. + // Empty arrays of user-defined types in custom attributes should compile successfully. + // The element type is substituted with System.Object since no elements need encoding. + // Previously this caused FS0192 internal error in encodeCustomAttrElemType. [] let ``Issue 12796 - DefaultValue empty array on record field of array type should not cause internal error`` () = FSharp @@ -94,5 +95,4 @@ type B = { [] BField: A[] } """ |> asLibrary |> compile - |> shouldFail - |> withErrorCode 3885 + |> shouldSucceed From a0a1a5d493ca5bf9084b89339170a346b1f36186 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 14 Apr 2026 00:47:26 +0200 Subject: [PATCH 3/4] Add type annotation to fix FS0072 in bootstrap build The bootstrap compiler needs an explicit type annotation on the 'g' parameter in GenAttribArg to resolve g.ilg.typ_Object, since g's type is not constrained until later match cases (TypeOfExpr, EnumExpr, etc.). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/CodeGen/IlxGen.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index bf54687e09b..5092ffaab22 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -10182,7 +10182,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 From 97999961c884494eeb4a73298b7cf5fd4761ae6a Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 14 Apr 2026 01:04:22 +0200 Subject: [PATCH 4/4] Add enum and primitive empty array attribute tests for #12796 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Language/AttributeCheckingTests.fs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/FSharp.Compiler.ComponentTests/Language/AttributeCheckingTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/AttributeCheckingTests.fs index d50401ed2ef..d287806b954 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/AttributeCheckingTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/AttributeCheckingTests.fs @@ -96,3 +96,34 @@ type B = { [] BField: A[] } |> asLibrary |> compile |> shouldSucceed + + // https://github.com/dotnet/fsharp/issues/12796 + [] + let ``Issue 12796 - Empty array of enum type in attribute should succeed`` () = + FSharp + """ +module TestModule + +type MyEnum = A = 0 | B = 1 +type MyAttr(v: obj) = inherit System.Attribute() +type T = { [] F: int } + """ + |> asLibrary + |> compile + |> shouldSucceed + + // https://github.com/dotnet/fsharp/issues/12796 + [] + let ``Issue 12796 - Empty array of primitive type in attribute should succeed`` () = + FSharp + """ +module TestModule + +type MyAttr(v: int[]) = inherit System.Attribute() +type T = { [] F: int } + """ + |> asLibrary + |> compile + |> shouldSucceed + +