Expected <T> found <some_other_T>

I am ripping my hair out due to E0308 "Expected (someT) found (someOtherT)"

The error message must tell me WHO expects (someT) but there is no further info.

I cannot find anywhere in my code in which this expectation should be true.
Which code expects this to be the case?!

Is there some further error info that tells us more about the 2 sides of this unfulfilled contract and where they are coming from?

Please run the command cargo check in in a terminal (if you are using an IDE, do not only look there) and post the output of that so we can look. It will (almost always) indicate the relevant parts of the code. Once you have that, also post the code of the function that contains the error.

2 Likes

Thank you!

I did not know about cargo check command. I will try this and report if this provides the caller expectation reference, as hoped for.

In this particular case, I will try to make an isolated example, but the original issue was a crate API call that I am not using anymore, and casting a struct where I had an Option and it claimed to expect a String when I clearly specified an Option and I was calling the compiler a liar, which is not likely, of course, as I'm the human (error prone)... but perhaps cargo check tells me both sides... will investigate and reply. thank you for your answer!

Stand-alone examples are good, of course, but I don't mean that you necessarily need to make one — just that when you share the full error report from cargo check, it will likely be useful to also share the code of the function, so we can see some of the context you have and we don’t. Then we can try to explain what the compiler meant.

Ok,
So, even cargo check only outputs the same error info as when cargo run
I cannot figure out where the expectation for a String comes from, when I clearly specify an Option in both the struct and the new function.

example:

error[E0308]: mismatched types
   --> src/sofa_eater.rs:344:26
    |
344 |                     Some(trans.deliveryInfo), //email_delivery_info
    |                     ---- ^^^^^^^^^^^^^^^^^^ expected `String`, found `Option<String>`
    |                     |
    |                     arguments to this enum variant are incorrect
    |
    = note: expected struct `std::string::String`
                 found enum `std::option::Option<std::string::String>`
help: the type constructed contains `std::option::Option<std::string::String>` due to the type of the argument passed
   --> src/sofa_eater.rs:344:21
    |
344 |                     Some(trans.deliveryInfo), //email_delivery_info
    |                     ^^^^^------------------^
    |                          |
    |                          this argument influences the type of `Some`
note: tuple variant defined here
   --> /home/aaron/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:579:5
    |
579 |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
    |     ^^^^
help: consider using `Option::expect` to unwrap the `std::option::Option<std::string::String>` value, panicking if the value is an `Option::None`
    |
344 |                     Some(trans.deliveryInfo.expect("REASON")), //email_delivery_info
    |                                            +++++++++++++++++

error[E0308]: mismatched types
   --> src/sofa_eater.rs:345:26
    |
345 |                     Some(trans.smsIdTwilio), //sms_id_twilio
    |                     ---- ^^^^^^^^^^^^^^^^^ expected `String`, found `Option<String>`
    |                     |
    |                     arguments to this enum variant are incorrect
    |
    = note: expected struct `std::string::String`
                 found enum `std::option::Option<std::string::String>`
help: the type constructed contains `std::option::Option<std::string::String>` due to the type of the argument passed
   --> src/sofa_eater.rs:345:21
    |
345 |                     Some(trans.smsIdTwilio), //sms_id_twilio
    |                     ^^^^^-----------------^
    |                          |
    |                          this argument influences the type of `Some`
note: tuple variant defined here
   --> /home/aaron/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:579:5
    |
579 |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
    |     ^^^^
help: consider using `Option::expect` to unwrap the `std::option::Option<std::string::String>` value, panicking if the value is an `Option::None`
    |
345 |                     Some(trans.smsIdTwilio.expect("REASON")), //sms_id_twilio
    |                                           +++++++++++++++++

error[E0308]: mismatched types
   --> src/sofa_eater.rs:346:26
    |
346 |                     Some(trans.sms_twilio_date_updated),
    |                     ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `String`, found `Option<String>`
    |                     |
    |                     arguments to this enum variant are incorrect
    |
    = note: expected struct `std::string::String`
                 found enum `std::option::Option<std::string::String>`
help: the type constructed contains `std::option::Option<std::string::String>` due to the type of the argument passed
   --> src/sofa_eater.rs:346:21
    |
346 |                     Some(trans.sms_twilio_date_updated),
    |                     ^^^^^-----------------------------^
    |                          |
    |                          this argument influences the type of `Some`
note: tuple variant defined here
   --> /home/aaron/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:579:5
    |
579 |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
    |     ^^^^
help: consider using `Option::expect` to unwrap the `std::option::Option<std::string::String>` value, panicking if the value is an `Option::None`
    |
346 |                     Some(trans.sms_twilio_date_updated.expect("REASON")),
    |                                                       +++++++++++++++++

and the struct that is being instantiated, which should specify the expected part, right?

pub struct OldTransaction {
	pub id: i64,
	pub sender: i32,
	pub chosen_card: i64,
	pub datetime_sent: Option<String>,
	pub rcvr: String,
	pub rsvp_answer: Option<String>,
	pub rsvp_comments: Option<String>,
	pub reply_to_sender: Option<String>,
	pub email_delivery_info: Option<String>,
	pub sms_id_twilio: Option<String>,
	pub sms_twilio_date_updated: Option<String>,
	pub public_id: String,
}


	pub async fn new ( sender: i32,chosen_card: i64,datetime_sent: Option<String>,rcvr: String,rsvp_answer: Option<String>,rsvp_comments: Option<String>,reply_to_sender: Option<String>,email_delivery_info: Option<String>,sms_id_twilio: Option<String>,sms_twilio_date_updated: Option<String>,public_id: String )  -> Result<i64, sqlx::Error> {
		let rec = sqlx::query!(
			r#"
			INSERT INTO old_transaction (sender,chosen_card,datetime_sent,rcvr,rsvp_answer,rsvp_comments,reply_to_sender,email_delivery_info,sms_id_twilio,sms_twilio_date_updated,public_id)
			VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)
			ON CONFLICT DO NOTHING
			RETURNING id
			"#,sender,chosen_card,datetime_sent,rcvr,rsvp_answer,rsvp_comments,reply_to_sender,email_delivery_info,sms_id_twilio,sms_twilio_date_updated,public_id)
		.fetch_one(get_db_pool())
		.await?;
		Ok(rec.id)
	}

when calling this function and instantiating this struct

                  let new_old_transaction = crate::models::old_transaction::OldTransaction::new (
                    owner, //sender
                    new_card_id, //chosen_card
                    Some(trans.timeUtc ), //datetime_sent
                    trans.whichRecipient, //rcvr
                    trans.rsvpAnswer, //rsvp_answer
                    trans.rsvpComments, //rsvp_comments
                    trans.reply, //reply_to_sender
                    Some(trans.deliveryInfo), //email_delivery_info
                    Some(trans.smsIdTwilio), //sms_id_twilio
                    Some(trans.sms_twilio_date_updated),
                    trans._id, //public_id
                  ).await.unwrap();

I would love to know where the compiler got the notion that it wanted a String...

trans.sms_twilio_date_updated is already Option<String>, by wrapping it in Some() you are wrapping it with an extra Option.

2 Likes

Ok, thank you!

However, this does not explain where the compiler got the idea that it should be a String. (expected a String, found an Option )

I mean, wouldn't it be nice if the compiler said:
"hey look, bozo, YOU said xyz on line 43:34, which leads us to expect xyz on other_mod line 55:12 where you told us pdq"

I see multiple topics here where other magical/deductive powers of reasoning were used to figure out the error, when the compiler probably knows darn well where the 2 sides of this alleged contract live, and why not simple tell us, etc.

but yes, that would fix this error caused by my human (error prone, noob) self.
Thank you, Firebits.io ! :pray: :pray: :pray: :medal_military: :gift:

It does. The compiler expected Option<String> and you provided Option<Option<String>>. Then it "reasoned" that the expected type inside Option was String, but the Option that you provided it contained Option<String> , hence the error message "expected String, got Option<String>".

1 Like

The ^^^ points to the value that it is referring to, if that helps.

1 Like

ok, where does this "reasoning" occur? is there a way to get the "raw" error?

It's just how generics work. Option is an enum that receives a generic type parameter.

Maybe an analogy could help here:

You told the compiler that you were going to give it a toy inside a box, but you gave it a toy inside a box, inside another box.

Then the compiler complained telling you that it expected the toy to be inside a box but, after opening the box, it found another box containing the toy.

2 Likes

right, and this was the part where I was calling the compiler a liar, as I didn't specify a String, but apparently there is some unwrapping of the option due to me having double-option-wrapped it...

I guess i am ultimately asking for a compiler error E0308 that states:
expected String due to line 123, found Option<String> right here

or somesuch... (a reference to the source of the expectation, where the error already points to the wrongful value provided, the second part of this contract i am referring to)

but i also appreciate the Option<T> lesson

That reference is the type system. Rust is statically typed, and when you declared the new function, you told the compiler that it was going to receive an argument with the type Option<String> in that position.

pub async fn new ( sender: i32,chosen_card: i64,datetime_sent: Option<String>,rcvr: String,rsvp_answer: Option<String>,rsvp_comments: Option<String>,reply_to_sender: Option<String>,email_delivery_info: Option<String>,sms_id_twilio: Option<String>,sms_twilio_date_updated: Option<String>,public_id: String )  -> Result<i64, sqlx::Error> {

... which led me to wonder why the compiler seems to expect a String, and complains when I provide it a (mistaken Option<Option<String>> ) Option<String>

when I defined OldTransaction such that it should be an Option<String> and yet the compiler expects a String, that is implicit magical unwrapping or? that part I still don't get...

It's not implicit unwrapping. It's common lingo to refer to types such as Option as container types, and having compiler diagnostics use this concept when describing the compilation error.

Basically, the error message was trying to be smart and tell you that the type inside the Option didn't match what it expected. I can totally see why it tripped you out, but once you understand it you'll be able to see that it's not as bad as it seems.

Tomorrow I'll try to check if anyone else has already filled an issue to improve this particular error message.

2 Likes

Thank you :pray: :pray: :pray:

I don't have much to add, except to chime in that when I see expected/found diagnostics like

4 |     call(value);
  |     ---- ^^^^^ expected `Option<String>`, found `Option<Option<String>>`
  |     |
  |     arguments to this function are incorrect

it is not always clear to me whether it means

I expected value to be an Option<String> because that's what call takes, but instead I found that value is an Option<Option<String>>.

Or

I expected call to take an Option<String> because that's what value is, but instead I found that call takes an Option<Option<String>>.

Often both are equally plausible to me; why should I know from whence the compiler is drawing its expectations? And...

  = note: expected enum `Option<String>`
             found enum `Option<Option<String>>`

Not helpful! Tell me what "expected" actually is (or came from), or what you "found", in terms of my code.

  // I wish it said one or all of
  = note: found that `value` is an enum `Option<Option<String>>`
  = note: expected enum `Option<String>` due to `call`'s signature

(Disclaimer: the minimized code I used to generate these examples does actually contain enough extra notes to be clear, but I have definitely had ones that did not, probably due to generics and indirection.[1])

((I thought I'd seen a general issue for this but didn't find one. However, I did find that the found/expected order has changed for multiple cases! But also that, apparently, others have more of an intuition for which should be "found" or "expected" than I do.))


  1. Or maybe the compiler has improved lately. ↩︎

1 Like