You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
SRTP "member get_Item" causes "FS0192: internal error" when used on strings #18093
Please provide a succinct description of the issue.
I was attempting to index into array-like collections using SRTP and encountered the error using strings. It appears the underlying cause is that the indexer method is not necessarily get_Item and may be overridden using [<IndexerName>]. This is the case in String.cs with the attribute [IndexerName("Chars")] that results in a get_Chars method instead of get_Item.
Provide the steps required to reproduce the problem:
It can be reproduced using FSI
let inlineindexInto(slice:^Twhen^T:(member get_Item:int ->^U))i :^U=slice.get_Item ilet array =[|1;2;3;4;5 |]//Oklet list =ResizeArray<int>(array)//Oklet str = "abcde"
printfn $"{indexInto array 2}" //Okprintfn $"{indexInto list 2}" //Okprintfn $"{indexInto str 2}" //error FS0192:internal error:unknown builtin witness 'get_ItemDynamic'let inline indexChars (slice:^T when ^T:(member get_Chars:int ->^U))i :^U=slice.get_Chars iprintfn $"{indexChars array 2}" //The type 'int array' does not support the operator 'get_Chars'printfn $"{indexChars str 2}" //Ok
Expected behavior
My initial expectation was that indexInto would allow indexing into any type that had an indexer (using either get_Item or [i]) but after learning about [<IndexerName>] I'm no longer sure if this should be the case. Some suggestions for a resolution:
Change the compiler's understanding of member get_Item in SRTP
Make get_Item a compiler-known method that checks for usage of [<IndexerName>] on the target type and inserts the appropriate call.
Despite being "magical" this is probably the expected behavior of most F# developers unaware of the existence of [<IndexerName>].
Change the error and provide alternate mechanism to combine SRTP and indexers
The error should become "The type 'string' does not support the operator 'get_Item'" rather than "FS0192 internal error" to match other type errors.
Consider some other syntax to allow indexers to be accessed for all types using SRTP:
member []
member Item[]
[<Indexer>] member get_Item
member op_Item
let inlineindexInto(slice:^Twhen^T:(member[]:int ->^U))i :^U=slice.[i]//or slice[i]
Known workarounds
Instead of SRTP, use interfaces to access elements (it's noteworthy that String doesn't implement IReadOnlyList which would seem appropriate for this case)
Use Span which unifies some indexable types but has other usage limitations
Wrap the string and re-implement the indexer
[<Struct>]typeWrapper=| Wrapper ofstringmemberthis.Itemwith get i =let(Wrapper s)= this
s.[i]
printfn $"{indexInto (Wrapper str) 2}"
This is an unfortunate consequence on how indexer for strings is done.
I don't think I have seen this used elsewhere, in any other common type.
From the proposals, the member [] syntax looks good and would also enable dropping the get_Item workaround/limitation. For treating it as a bugfix though, I am afraid the audience for this issue is too small to justify a language change (happy to be corrected! ).
Either a change of the compiler message, or a known compile-time replacement from get_Item into any method with the [<IndexerName>] attribute are more likely.
Thank you for describing the issue in depth and listing good workarounds - this will be a nice reference in case anyone else encounters the limitation for the intersection of SRTP's and indexing into a string.
One-line typo fix in src/Compiler/TypedTree/TcGlobals.fs at TryMakeOperatorAsBuiltInWitnessInfo (~line 1932).
The string case for get_Item matches [stringTy; _; _] (3 elements) but CompiledObjectAndArgumentTypes for string.get_Item(int) is [stringTy; intTy] (2 elements). It never matches, falls through to failwithf.
Change:
|"get_Item",[stringTy;_;_],_,[_;_]when isStringTy g stringTy ->
to:
|"get_Item",[stringTy;_],_,[_;_]when isStringTy g stringTy ->
Instructions
Use TDD: write a test first that reproduces let inline indexInto (s: ^a) i = (^a: (member get_Item: int -> ^b) (s, i)) in indexInto "abc" 2 failing with FS0192, then fix.
Run related tests: dotnet test tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj --filter "SRTP" -c Debug
After code change, invoke the expert-review skill to review your work.
Minimal surgical fix. No bloated comments. This is an expert-level codebase.
Activity
T-Gro commentedon Dec 2, 2024
This is an unfortunate consequence on how indexer for strings is done.
I don't think I have seen this used elsewhere, in any other common type.
From the proposals, the
member []syntax looks good and would also enable dropping theget_Itemworkaround/limitation. For treating it as a bugfix though, I am afraid the audience for this issue is too small to justify a language change (happy to be corrected! ).Either a change of the compiler message, or a known compile-time replacement from
get_Iteminto any method with the[<IndexerName>]attribute are more likely.Thank you for describing the issue in depth and listing good workarounds - this will be a nice reference in case anyone else encounters the limitation for the intersection of SRTP's and indexing into a string.
T-Gro commentedon May 18, 2026
🤖 Copilot implementation hints
Fix
One-line typo fix in
src/Compiler/TypedTree/TcGlobals.fsatTryMakeOperatorAsBuiltInWitnessInfo(~line 1932).The string case for
get_Itemmatches[stringTy; _; _](3 elements) butCompiledObjectAndArgumentTypesforstring.get_Item(int)is[stringTy; intTy](2 elements). It never matches, falls through tofailwithf.Change:
to:
Instructions
let inline indexInto (s: ^a) i = (^a: (member get_Item: int -> ^b) (s, i)) in indexInto "abc" 2failing with FS0192, then fix.dotnet test tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj --filter "SRTP" -c Debugexpert-reviewskill to review your work.dotnet fantomas .on changed files.