Skip to main content

Module r_shadowing

Module r_shadowing 

Source
Expand description

Calls to base functions that a formal of the same name would shadow.

Generated R wrappers call base functions by their bare names: the precondition guards call isTRUE() and length(), a choice formal’s default is c("a", "b"), a Missing<T> argument is forwarded as if (missing(x)) quote(expr=) else x, the check after .Call() calls inherits() and attr(), and dots are forwarded as list(...) (or, for LazyDots, the frame as environment()). R looks up the name of a called function starting in the wrapper’s own frame, so a formal with the same name comes first: forcing it fails when the argument was omitted, and a function passed there is called in place of the base function.

The rule: inside a generated wrapper, a call to one of these base functions always means the base function, even when a formal has that name. qualify_shadowed_calls writes base::length(...) for each call whose name is also a formal of the wrapper, and leaves every other call alone. It runs where every wrapper is finalized (r_wrapper_raw_literal), so no emitter can leave it out, and the author R code spliced into a wrapper (r_entry, r_on_exit, r_post_checks, parameter defaults) is qualified the same way.

A formal is a Rust parameter name without its leading underscores and without r#, unless the parameter declares its R name with formal (#1842). A Rust identifier cannot contain ., so only a declared formal can be named is.character, match.call or .Call: dotted base callees are listed and qualified like the others. A declared formal can’t take a name of the framework’s own (.miniextendr_arg_error, .mx_self, .call, .Generic; r_wrapper_builder::declared_formal_problem), so the calls to those are never qualified.

Only the colliding calls are qualified because :: costs time on every call: the byte compiler compiles base::f(x) as a call to the :: primitive instead of inlining f. On a byte-compiled one-argument wrapper, qualifying the guards added about 200 ns per call (+19%), and qualifying every call about 475 ns (+44%). When no formal collides, the text is returned unchanged.

Three generators do not finalize through here: the sidecar accessors of #[derive(ExternalPtr)], the functions #[derive(Vctrs)] emits and the all.equal() methods of #[derive(AllEqual)]. Their formals are fixed (x, value, to, target, current, tolerance, scale, …), and none of their bodies calls a function of one of those names.

Constants§

BASE_CALLEES 🔒
The base functions that generated wrapper text calls by their bare names.

Functions§

formal_names 🔒
The R formals of every wrapper built from signatures, each a parameter list with the formals it declares: the union of each signature’s r_formal_names.
ident_end 🔒
End of the identifier (or number) starting at start.
identifiers 🔒
Byte ranges of the R identifiers in text, skipping strings ("...", '...'), raw strings (r"(...)", R'[...]', r"-{...}-"), comments, backtick names, %op% operators and numbers.
infix_end 🔒
End of the %op% operator starting at start, or just past the % when the line has no closing %.
is_accessed 🔒
Whether the identifier starting at start follows ::, :::, $ or @, so it names a namespace export or a member, not a function in scope.
is_call 🔒
Whether the identifier ending at end is called: followed by optional spaces and (.
qualify_shadowed_calls 🔒
Write base:: before every call in text to a BASE_CALLEES function that shares its name with one of formals.
quoted_end 🔒
End of the string or backtick name opened by quote at start, after its closing quote. A backslash escapes the next character.
raw_string_end 🔒
End of the raw string whose quote is at quote_at, right after an r or R: the quote, any dashes, and an opening (, [ or {, closed by the matching bracket, the same dashes and the same quote. None when the quote does not open a raw string.