Skip to content

Benign race condition in graph based type checking of type extensions but breaks determinism #19033

@majocha

Description

@majocha

This is a race condition in a very specific scenario when we have two or more type extensions of the same type in two independent (from graph checking pov) files:

// Update resolved type parameters with the names from the source.
let _, tcref, _ = res
if tcref.TyparsNoRange.Length = synTypars.Length then
(tcref.TyparsNoRange, synTypars)
||> List.zip
|> List.iter (fun (typar, SynTyparDecl.SynTyparDecl (typar = tp)) ->
let (SynTypar(ident = untypedIdent; staticReq = sr)) = tp
if typar.StaticReq = sr then
typar.SetIdent(untypedIdent)
)

If each extension updates the type var name, we have a race during parallel checking. In effect some of the extensions will end up with a randomly wrong typar name.

This happens when compiling FCS.dll using graph based type checking because LexBuffer<_> has such multiple independent extensions: #19028 (comment)

Repro steps

SetIdentRace repo or

SetIdentRace.zip

dotnet build --no-incremental a few times.

observe the dumped sigdata or inspect dll:

correct with sequential checking:

Image

wrong with graph based (Print<'X> instead of Print<'U>):
Image

This is not very severe and rather an edge case, apart from the fact that it prevents graph based type checking from being deterministic.

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    Status

    New

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions