Make procedural macro compilation error point inside a token - rust

When reporting errors in macros like println! Rust compiler shows the precise location within the format string where something has gone wrong, e.g.:
11 | println!("I'm going to substitute {foo}... or not");
| ^^^^^ not found in this scope
How I do the same thing for my format!-like macro? Both ways of reporting errors in procedural macro (quote_spanned! + compile_error! or the experimental Diagnostic API) rely on proc_macro::Span and I don't see a way to construct a Span for a location inside a token, even via experimental APIs.

Related

How to make sure that a Rust attribute proc macro runs before the compiler tries parsing the item?

I'm trying to make a macro that adds some extra syntax to struct type declarations.
For simplicity, here's a toy example: a macro that replaces "function call"-style type declarations with normal ones.
#[my_macro]
struct Point {
x: LiteralType("f32"),
y: LiteralType("f32"),
}
should turn into
struct Point {
x: f32,
y: f32,
}
From the output of my code and cargo expand, I can tell that my code produces the correct syntax.
However, before that happens, the compiler has already tried parsing the LiteralType("f32") syntax, failed and emitted an error saying as much, and now the whole build fails.
I think I need to somehow force the compiler to run my macro's code to completion before trying to parse it according to the regular Rust rules. I think it might be possible to do using functional macros, because those can accept syntax that's much more unusual, but I'd prefer to stick with attribute macros because those provide a secondary input for attributes.
You cannot do that with attribute macros, they always validate their items.
But as you said, you can do that with function-like macros.

Is there a pattern to change compile behavior based on a type (proc macros)

I am trying to write a procedural macro that performs different behavior based on a trait type, which the macro may not have access to. For example, given the following trait:
trait Bar {
type BarType;
}
I would like to be able to change macro behavior based on the chosen BarType, even when my macro may not have direct access to it:
// This macro sees nothing about BarType
#[macro_option_1]
struct Foo {}
// this macro sees nothing about BarType
macro_option_2!(Foo);
// This location works but is not desirable
// #[working_macro_option]
impl Bar for Foo {
type BarType = Option<u32>;
}
A macro at working_macro_option would have access to BarType, but this location is not desirable (as my actual macro needs to work with multiple traits). So, my goal is to be able to use a macro that works at either macro_option_1 or macro_option_2, which have no useful content available to parse.
I am hoping for a pattern along the lines of what quote_spanned makes possible (link to example), but changing what the macro does in some way. So, I believe this needs to be something that's directly compilable, rather than something possible only in proc macros.
(this is unfortunately outside the scope of generics - my macro needs to create a function with a completely different signature based on type, for a C FFI)
Edit: more context on my end goal.
I am writing a library that helps users create a UDF, which is a dylib with a C interface. The init, process, add, remove etc. functions map nicely to traits (see my unfinished work here). My goal is that a user of my library can:
Define a struct or enum (which may be zero-sized, or contain something useful) which will give their UDF name
Implement my traits on this struct (one trait is required, the second is optional)
Add a #[register] macro to this struct
And from there, my library will generate the correct C interface functions via the macro. This isn't too different from how PyO3 works, I believe.
However, some of the C function signatures depend on the Return type within BasicUdf, so my macro needs some way to know what this is. I find it cleaner to put the macro on the main struct, so I am looking for a way to do this (hence this question)
My backup plan is to require placing the macro on the impl, which isn't terrible but is just less elegent (parsing the Returns type there is no problem). Something like a PhantomData marker on the main struct would also work, but I don't find that too ergonomic.

Why can a variable be formatted, but not an element of an array when using the println macro?

Say you have
let x: u8 = 1
println!("{x}");
this works fine; however, if you instead have
let x: [u8; 1] = [1];
println!("{x[0]}");
then it throws the error
error: invalid format string: expected `'}'`, found `'['
|
| println!("{x[0]}");
| - ^ expected `}` in format string
| |
| because of this opening brace
|
= note: if you intended to print `{`, you can escape it using `{{`
why is this?
The inline print functionality is only intended for variable names. To be honest though, I rarely see this syntax used though. Most people prefer println!("{}", x[0]) instead, and this is one of the main reasons why.
I can defiantly see where they were coming from though. The {:?} or {:X} syntax might look weird since the colon does not seem to have a use in these statements to print in debug or hexadecimal mode, but I suspect it was made to mirror fields in structs and function arguments. It starts to look more familiar when you write it with the inline variable and spacing: format!("{name: ?}"). Under this reasoning it makes more sense to only allow idents here (Token for an identity. Essentially the name of a variable/type/module/etc). But this didn't really materialize (if it ever even was a thing) so we don't have this syntax.
Personally, I think they could have made it work, but you would end up with confusion about how :? (and other format specifiers) work in regards to expressions. For example, if people are taught that {x.foo()} will print the display of the expression x.foo() then does that mean x.foo(): ? is also a valid expression? What about -3.0:3.0?? It kinda looks like a range in python, but I have just worded it in a confusing way.
Edit: Found the RFC for this: https://rust-lang.github.io/rfcs/1618-ergonomic-format-args.html
Edit 2: I found a Rust forum post which better addresses your question (https://internals.rust-lang.org/t/how-to-allow-arbitrary-expressions-in-format-strings/15812). Their reasoning is as follows:
Curly braces in format strings are escaped with curly braces: format!("{{foo}}") prints {foo}. If arbitrary expressions were supported, parsing this would become ambiguous.
It's ambiguous when type ascription is enabled: format!("{foo:X}") could mean either type ascription or that the UpperHex trait should be used.
The ? operator could be easily confused with Debug formatting: "{foo?}" and "{foo:?}" look very similar.

How cfg are dealt with in rustc?

This is a further question on How to extract nightly features used in a crate?.
I also want to know where and how #![cfg_attr(target_os = "macos", feature(...))] is turned into #![feature(...).
Could someone give me some tips about the process of rustc dealing with cfg.
The rustc_expand crate is responsible for expanding macros. It special cases #[cfg] and #[cfg_attr] when parsing attribute macros such that they aren't treated like normal macros.
rustc_expand calls rustc_parse::parse_cfg_attr to parse the attribute.
With the parsed macro, rustc_expand calls rustc_attr::cfg_matches to evaluate if the condition is met.
rustc_expand then either includes or doesn't include the attribute passed as an argument.

No method write found in TcpStream in rust [duplicate]

I tried to compile the following program:
use std::io;
fn main() {
io::stdout().write(b"Please enter your name: ");
io::stdout().flush();
}
Unfortunately, compiler resisted:
error: no method named `write` found for type `std::io::Stdout` in the current scope
--> hello.rs:4:18
|
4 | io::stdout().write(b"Please enter your name: ");
| ^^^^^
|
= help: items from traits can only be used if the trait is in scope; the following trait is implemented but not in scope, perhaps add a `use` for it:
= help: candidate #1: `use std::io::Write`
I found that I needed to do use std::io::{self, Write};. What does use std::io; actually do then and how do (if possible) I pull all names defined in std::io? Also, would it be a bad style?
What does use std::io; actually do then?
It does what every use-statement does: makes the last part of the used path directly available (pulling it into the current namespace). That means that you can write io and the compiler knows that you mean std::io.
How do I pull all names defined in std::io?
With use std::io::*;. This is commonly referred to as glob-import.
Also, would it be a bad style?
Yes, it would. Usually you should avoid glob-imports. They can be handy for certain situations, but cause a lot of trouble on most cases. For example, there is also the trait std::fmt::Write... so importing everything from fmt and io would possibly result in name-clashes. Rust values explicitness over implicitness, so rather avoid glob-imports.
However, there is one type of module that is usually used with a glob-import: preludes. And in fact, there is even a std::io::prelude which reexports important symbols. See the documentation for more information.

Resources