Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Option type try block require a type annotation?

Tags:

rust

compiler: rustc 1.71.0-nightly (c609da59d 2023-04-18)

I tried nightly #![feature(try_blocks)] with this:

#![feature(try_blocks)]
fn test_try(input: Option<i32>) {
    let output = try {
        input?
    };

    println!("{:?}", output);
}

But the compiler claims that output needed type annotations. Full error message is here:

error[E0282]: type annotations needed
 --> src/main.rs:3:9
  |
3 |     let output = try {
  |         ^^^^^^
  |
help: consider giving `output` an explicit type
  |
3 |     let output: /* Type */ = try {
  |               ++++++++++++

If I tried let output: Option<i32> = ... everything works fine.

It seems output should be Option<i32> but the compiler does not infer that.

Is it just because the feature is unstable or did I miss something? Any other type than Option<i32> is possible for output?

like image 488
Donghyeon Lee Avatar asked Sep 08 '25 17:09

Donghyeon Lee


1 Answers

The try_blocks feature is mostly unstable because of inference problems. The design of the Try trait (that powers try blocks and the ? operator) makes it very flexible, but also very hard for the compiler to infer the type.

In std there is nothing except Option<i32> that can be the result of this expression. But one can write one, because the thing that drives the desugaring of the try block is not the types that are ?ed in it, but the type that it results to. So it can be anything, as long as it supports ?ing Option<i32>. For example:

#![feature(try_blocks, try_trait_v2)]

use std::convert::Infallible;
use std::ops::ControlFlow;

#[derive(Debug)]
struct MyFancyType;

impl std::ops::FromResidual<Option<Infallible>> for MyFancyType {
    fn from_residual(_residual: Option<Infallible>) -> Self {
        Self
    }
}

impl std::ops::FromResidual for MyFancyType {
    fn from_residual(_residual: Infallible) -> Self {
        Self
    }
}

impl std::ops::Try for MyFancyType {
    type Output = i32;
    type Residual = Infallible;

    fn from_output(_output: i32) -> Self {
        Self
    }

    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
        ControlFlow::Continue(0)
    }
}

fn test_try(input: Option<i32>) {
    let output: MyFancyType = try { input? };

    println!("{:?}", output);
}

Playground.

like image 152
Chayim Friedman Avatar answered Sep 10 '25 18:09

Chayim Friedman