Repository: servo/servo
File: components/script/dom/webgl/webglprogram.rs (Rust)

Code before:
                    }
                },
                None => return Err(WebGLError::InvalidOperation),
            },
            None => return Err(WebGLError::InvalidOperation),
        }

        *shader_slot = None;
        shader.decrement_attached_counter();

        self.send_command(WebGLCommand::DetachShader(self.id, shader.id()));

        Ok(shader)
    }

    fn detach_shaders(&mut self) {
        if let Some(ref mut shader) = self.fragment_shader {
            if let Some(root) = shader.root() {
                root.decrement_attached_counter();
            }
            self.fragment_shader = None;
        }
        if let Some(ref mut shader) = self.vertex_shader {
            if let Some(root) = shader.root() {
                root.decrement_attached_counter();
            }
            self.vertex_shader = None;
        }
    }
}

impl DroppableWebGLProgram {
    fn is_deleted(&self) -> bool {
        self.marked_for_deletion.get() && !self.is_in_use.get()
    }

    fn send_command(&self, command: WebGLCommand) {
        self.send_with_fallibility(command, Operation::Infallible);
    }

    fn send_with_fallibility(&self, command: WebGLCommand, fallibility: Operation) {
        if let Some(root) = self.context.root() {
            let result = root.sender().send(command, capture_webgl_backtrace());
            if matches!(fallibility, Operation::Infallible) {
                result.expect("Operation failed");
            }
        }
    }

    fn mark_for_deletion(&mut self, operation_fallibility: Operation) {
        if self.marked_for_deletion.get() {

Review comment (suggestion):
Since detach_shader exists, let's use it. I think we should be able to do:
```rust
if let Some(ref shader) = self.fragment_shader {
    if let Some(root) = shader.root() {
        let _ = self.detach_shader(&root);
    }
    self.fragment_shader = None;
}
// etc.
```

Code after:
        }

        *shader_slot = None;
        shader.decrement_attached_counter();

        self.send_command(WebGLCommand::DetachShader(self.id, shader.id()));

        Ok(shader)
    }

    fn detach_shaders(&mut self) {
        if let Some(ref mut shader) = self.fragment_shader {
            if let Some(root) = shader.root() {
                root.decrement_attached_counter();
                self.send_command(WebGLCommand::DetachShader(self.id, root.id()));
            }
            self.fragment_shader = None;
        }
        if let Some(ref mut shader) = self.vertex_shader {
            if let Some(root) = shader.root() {
                root.decrement_attached_counter();
                self.send_command(WebGLCommand::DetachShader(self.id, root.id()));
            }
            self.vertex_shader = None;
        }
    }

    fn is_deleted(&self) -> bool {
        self.marked_for_deletion && !self.is_in_use
    }

    fn send_command(&self, command: WebGLCommand) {
        self.send_with_fallibility(command, Operation::Infallible);
    }

    fn send_with_fallibility(&self, command: WebGLCommand, fallibility: Operation) {
        if let Some(root) = self.context.root() {
            let result = root.sender().send(command, capture_webgl_backtrace());
            if matches!(fallibility, Operation::Infallible) {
                result.expect("Operation failed");
            }
        }
    }

    fn mark_for_deletion(&mut self, operation_fallibility: Operation) {
        if self.marked_for_deletion {
            return;
        }
        self.marked_for_deletion = true;
        self.send_with_fallibility(WebGLCommand::DeleteProgram(self.id), operation_fallibility);
        if self.is_deleted() {