Skip to content

Next-gen solver: Compiler "hang" & eventual OOM when facing complex mutually recursive structs & many projections #126196

Closed
@fmease

Description

@fmease

Context / History

The original issue is a rustdoc[old solver] compiletime issue: #114891.
I was able to reduce that issue to 211 LOC: #114891 (comment).

I then looked into switching rustdoc's blanket impl synthesizer to use the next solver: #125907.
Ignoring the fact that that's blocked on perf, it would actually make #114891 (comment) hang and alloc until the OS's OOM killer swoops in.

Finally, the reproducer below (to be minimized) is the rustdoc[next solver] "MCVE" turned into a rustc[next solver] issue by "reifying" the obligations registered by blanket_impl as Rust code.

Fixing this issue would partially unblock #125907 / #114891.

Reproducer

Old solver: Error type annotations needed // cannot infer type of the type parameter T declared on the function check.
Next solver: Compiler hang & eventual OOM.

Reproducer (215 LOC)
use std::sync::{Mutex, RwLock};
use std::{
    collections::HashMap,
    sync::{Arc, Weak},
};

pub trait Api: Clone {
    type Instance: Instance<A = Self>;
    type Surface: Surface<A = Self>;
    type Adapter: Adapter<A = Self>;
    type Device: DeviceTr<A = Self>;

    type Queue: QueueTr<A = Self>;
    type CommandEncoder: CommandEncoder<A = Self>;

    type CommandBuffer: WasmNotSendSync;

    type Buffer: WasmNotSendSync + 'static;
    type Texture: WasmNotSendSync + 'static;
    type SurfaceTexture: WasmNotSendSync + std::borrow::Borrow<Self::Texture>;
    type TextureView: WasmNotSendSync;
    type Sampler: WasmNotSendSync;
    type QuerySet: WasmNotSendSync;
    type Fence: WasmNotSendSync;

    type BindGroupLayout: WasmNotSendSync;
    type BindGroup: WasmNotSendSync;
    type PipelineLayout: WasmNotSendSync;
    type ShaderModule: WasmNotSendSync;
    type RenderPipeline: WasmNotSendSync;
    type ComputePipeline: WasmNotSendSync;

    type AccelerationStructure: WasmNotSendSync + 'static;
}

pub trait Instance: Sized + WasmNotSendSync {
    type A: Api;
}

pub trait Surface: WasmNotSendSync {
    type A: Api;
}

pub trait Adapter: WasmNotSendSync {
    type A: Api;
}

pub trait DeviceTr: WasmNotSendSync {
    type A: Api;
}

pub trait QueueTr: WasmNotSendSync {
    type A: Api;
}

pub trait CommandEncoder: WasmNotSendSync {
    type A: Api;
}

pub trait WasmNotSendSync: WasmNotSend + WasmNotSync {}
impl<T: WasmNotSend + WasmNotSync> WasmNotSendSync for T {}

pub trait WasmNotSend: Send {}
impl<T: Send> WasmNotSend for T {}

pub trait WasmNotSync: Sync {}
impl<T: Sync> WasmNotSync for T {}

trait HalApi: Api + 'static {}

struct BindGroup<A: HalApi> {
    raw: A::BindGroup,
    device: Arc<Device<A>>,
    layout: Arc<A>,
    info: ResourceInfo<BindGroup<A>>,
    used: BindGroupStates<A>,
    used_buffer_ranges: Vec<A>,
    used_texture_ranges: Vec<A>,
}

struct BindGroupStates<A: HalApi> {
    buffers: BufferBindGroupState<A>,
    textures: TextureBindGroupState<A>,
    views: TextureView<A>,
    samplers: Sampler<A>,
}

type UsageScopePool<A> = Mutex<Vec<(BufferUsageScope<A>, TextureUsageScope<A>)>>;

struct Tracker<A: HalApi> {
    buffers: BufferTracker<A>,
    textures: TextureTracker<A>,
    views: TextureView<A>,
    samplers: Sampler<A>,
    bind_groups: crate::BindGroup<A>,
    compute_pipelines: A,
    render_pipelines: A,
    bundles: A,
    query_sets: QuerySet<A>,
}

struct BufferBindGroupState<A: HalApi> {
    buffers: Mutex<Vec<Arc<Buffer<A>>>>,
}
struct BufferUsageScope<A: HalApi> {
    metadata: Buffer<A>,
}

struct BufferTracker<A: HalApi> {
    metadata: Buffer<A>,
}

struct TextureBindGroupState<A: HalApi> {
    textures: Mutex<Vec<A>>,
}
struct TextureUsageScope<A: HalApi>(A);

struct TextureTracker<A: HalApi> {
    _phantom: std::marker::PhantomData<A>,
}

struct ResourceInfo<T> {
    marker: std::marker::PhantomData<T>,
}

struct Buffer<A: HalApi> {
    raw: A::Buffer,
    device: Arc<Device<A>>,
    info: ResourceInfo<Buffer<A>>,
    bind_groups: Mutex<Vec<Weak<BindGroup<A>>>>,
}

struct DestroyedBuffer<A: HalApi> {
    raw: Option<A::Buffer>,
    device: Arc<Device<A>>,
    bind_groups: Vec<Weak<BindGroup<A>>>,
}

struct StagingBuffer<A: HalApi> {
    raw: Mutex<Option<A::Buffer>>,
    device: Arc<Device<A>>,
    info: ResourceInfo<StagingBuffer<A>>,
}

enum TextureInner<A: HalApi> {
    Native(A::Texture),
    Surface(Option<A::SurfaceTexture>),
}

enum TextureClearMode<A: HalApi> {
    RenderPass(Vec<Option<A::TextureView>>),
    Surface(Option<A::TextureView>),
}

struct Texture<A: HalApi> {
    inner: TextureInner<A>,
    device: Arc<Device<A>>,
    info: ResourceInfo<Texture<A>>,
    clear_mode: RwLock<TextureClearMode<A>>,
    views: Mutex<Vec<Weak<TextureView<A>>>>,
    bind_groups: Mutex<Vec<Weak<BindGroup<A>>>>,
}

struct DestroyedTexture<A: HalApi> {
    raw: Option<A::Texture>,
    views: Vec<Weak<TextureView<A>>>,
    bind_groups: Vec<Weak<BindGroup<A>>>,
    device: Arc<Device<A>>,
}

struct TextureView<A: HalApi> {
    raw: A::TextureView,
    parent: Arc<Texture<A>>,
    device: Arc<Device<A>>,
    info: ResourceInfo<TextureView<A>>,
}

struct Sampler<A: HalApi> {
    raw: Option<A::Sampler>,
    device: Arc<Device<A>>,
    info: ResourceInfo<Self>,
}

struct QuerySet<A: HalApi> {
    raw: Option<A::QuerySet>,
    device: Arc<Device<A>>,
    info: ResourceInfo<Self>,
}

struct Device<A: HalApi> {
    raw: Option<A::Device>,
    adapter: Arc<A>,
    queue: Weak<Queue<A>>,
    queue_to_drop: A::Queue,
    zero_buffer: Option<A::Buffer>,
    info: ResourceInfo<Device<A>>,
    command_allocator: A,
    fence: RwLock<Option<A::Fence>>,
    trackers: Mutex<Tracker<A>>,
    life_tracker: Mutex<LifetimeTracker<A>>,
    temp_suspected: Mutex<Option<ResourceMaps<A>>>,
    pending_writes: Mutex<Option<PendingWrites<A>>>,
    usage_scopes: UsageScopePool<A>,
}

struct Queue<A: HalApi> {
    device: Option<Arc<Device<A>>>,
    raw: Option<A::Queue>,
    info: ResourceInfo<Queue<A>>,
}

struct EncoderInFlight<A: HalApi> {
    marker: std::marker::PhantomData<A>,
}
struct PendingWrites<A: HalApi> {
    command_encoder: A::CommandEncoder,
    dst_buffers: HashMap<i32, Arc<Buffer<A>>>,
    dst_textures: HashMap<i32, Arc<Texture<A>>>,
    executing_command_buffers: Vec<A::CommandBuffer>,
}

struct ResourceMaps<A: HalApi> {
    buffers: HashMap<i32, Arc<Buffer<A>>>,
    staging_buffers: HashMap<i32, Arc<StagingBuffer<A>>>,
    textures: HashMap<i32, Arc<Texture<A>>>,
    texture_views: HashMap<i32, Arc<TextureView<A>>>,
    samplers: HashMap<i32, Arc<Sampler<A>>>,
    bind_groups: HashMap<i32, Arc<BindGroup<A>>>,
    bind_group_layouts: HashMap<i32, Arc<A>>,
    render_pipelines: HashMap<i32, Arc<A>>,
    compute_pipelines: HashMap<i32, Arc<A>>,
    pipeline_layouts: HashMap<i32, Arc<A>>,
    render_bundles: HashMap<i32, Arc<A>>,
    query_sets: HashMap<i32, Arc<QuerySet<A>>>,
    destroyed_buffers: HashMap<i32, Arc<DestroyedBuffer<A>>>,
    destroyed_textures: HashMap<i32, Arc<DestroyedTexture<A>>>,
}
struct ActiveSubmission<A: HalApi> {
    last_resources: ResourceMaps<A>,
    mapped: Vec<Arc<Buffer<A>>>,
    encoders: Vec<EncoderInFlight<A>>,
}

struct LifetimeTracker<A: HalApi> {
    mapped: Vec<Arc<Buffer<A>>>,
    future_suspected_buffers: Vec<Arc<Buffer<A>>>,
    future_suspected_textures: Vec<Arc<Texture<A>>>,
    suspected_resources: ResourceMaps<A>,
    active: Vec<ActiveSubmission<A>>,
    ready_to_map: Vec<Arc<Buffer<A>>>,
}

fn main() {
    check::<BindGroup<_>>();
    fn check<T: WasmNotSync>() {}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-associated-itemsArea: Associated items (types, constants & functions)A-trait-systemArea: Trait systemC-bugCategory: This is a bug.E-needs-mcveCall for participation: This issue has a repro, but needs a Minimal Complete and Verifiable ExampleI-compilememIssue: Problems and improvements with respect to memory usage during compilation.I-compiletimeIssue: Problems and improvements with respect to compile times.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.WG-trait-system-refactorThe Rustc Trait System Refactor Initiative (-Znext-solver)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions