Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SRTP "member get_Item" causes "FS0192: internal error" when used on strings #18093

Open
roboz0r opened this issue Nov 30, 2024 · 1 comment
Open
Labels
Area-Compiler-SRTP bugs in SRTP inference, resolution, witness passing, code gen Bug Impact-Low (Internal MS Team use only) Describes an issue with limited impact on existing code.
Milestone

Comments

@roboz0r
Copy link

roboz0r commented Nov 30, 2024

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 inline indexInto (slice: ^T when ^T: (member get_Item: int -> ^U)) i : ^U =
    slice.get_Item i

let array = [| 1; 2; 3; 4; 5 |] // Ok
let list = ResizeArray<int>(array) // Ok
let str = "abcde" 

printfn $"{indexInto array 2}" // Ok
printfn $"{indexInto list 2}" // Ok
printfn $"{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 i

printfn $"{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:

  1. 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>].

  1. 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 inline indexInto (slice: ^T when ^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>]
type Wrapper =
    | Wrapper of string
    member this.Item with get i = 
        let (Wrapper s) = this
        s.[i]

printfn $"{indexInto (Wrapper str) 2}"
@T-Gro
Copy link
Member

T-Gro commented 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 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.

@0101 0101 added Area-Compiler-SRTP bugs in SRTP inference, resolution, witness passing, code gen Impact-Low (Internal MS Team use only) Describes an issue with limited impact on existing code. and removed Needs-Triage labels Dec 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compiler-SRTP bugs in SRTP inference, resolution, witness passing, code gen Bug Impact-Low (Internal MS Team use only) Describes an issue with limited impact on existing code.
Projects
Status: New
Development

No branches or pull requests

3 participants