slint-ui/slint · error · proc_macro::Error
Self pointer need to be the first
Error message
Self pointer need to be the first
What it means
When a vtable trait method takes self (VRef<Self>, VRefMut<Self> or &Self), that self-like pointer must be the first parameter so the macro can generate the correct dispatch thunks. If inputs precede the self parameter, the macro emits this compile error at the offending parameter.
Solutions
- Reorder so the self-like parameter (VRef, VRefMut, &Self) comes first.
- Pass extra context via the instance itself or via additional trailing parameters.
Example fix
// before fn draw(ctx: &RenderContext, self_: VRef<MyVTable>); // after fn draw(self_: VRef<MyVTable>, ctx: &RenderContext);
Defensive patterns
Strategy: validation
Validate before calling
// self-like parameter (VRef/VRefMut/&Self) must be first fn draw(self_: VRef<MyVTable>, ctx: &Ctx);
Prevention
- Adopt the convention: self parameter first, context/extra parameters after.
- When adding parameters to an existing vtable method, insert them after the self parameter.
When it happens
Trigger: Writing e.g. `fn draw(ctx: &Ctx, self_: VRef<MyVTable>)` — any trait method where a VRef/VRefMut/&Self parameter is not first.
Common situations: Porting from trait syntax where `self` is implicit and adding explicit arguments before it; designing methods with a context/state parameter first out of habit from other frameworks.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- VTable pointer need to be the first
- Only supported for structure with named fields
- The structure does not ends in 'VTable'
- The type of an #[field_offset] member in the vtable must be…
- VTable cannot be mutable
AI-assisted analysis of slint-ui/slint@bb937076de (2026-09-16).
Data as JSON: /api/errors/ae1e540185398313.
Report an issue: GitHub.
Appendix: source
Thrown at helper_crates/vtable/macro/macro.rs:340
call_code = Some(quote!(vtable as _,));
continue;
}
let (is_pin, self_ty) = match is_pin(¶m.ty) {
Some(t) => (true, t),
None => (false, ¶m.ty),
};
// check for self
if let (true, mutability) = if match_generic_type(self_ty, "VRef", &vtable_name) {
(true, None)
} else if match_generic_type(self_ty, "VRefMut", &vtable_name) {
(true, Some(Default::default()))
} else {
(false, None)
} {
if !sig.inputs.is_empty() {
return Error::new(param.span(), "Self pointer need to be the first")
.to_compile_error()
.into();
}
let const_or_mut = mutability.map_or_else(|| quote!(const), |x| quote!(#x));
has_self = true;
if !is_pin {
sig.inputs.push(FnArg::Receiver(Receiver {
attrs: param.attrs.clone(),
mutability: None,
self_token: Default::default(),
kind: ReceiverKind::Reference(Default::default(), None, mutability),
}));
call_code =
Some(quote!(#call_code <#self_ty>::from_raw(self.vtable, self.ptr),));
self_call =
Some(quote!(&#mutability (*(#arg_name.as_ptr() as *#const_or_mut T)),));
} else {View on GitHub (pinned to bb937076de)