From 8047512dcab33780276771d398ddaee20ec8e933 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 18 Oct 2022 14:18:59 +0200 Subject: [PATCH] Revert "feat: Diagnose some incorrect usages of the question mark operator" --- crates/hir-expand/src/mod_path.rs | 1 - crates/hir-expand/src/name.rs | 2 - crates/hir-ty/src/infer.rs | 13 ++- crates/hir-ty/src/infer/expr.rs | 99 ++----------------- crates/hir-ty/src/method_resolution.rs | 18 ---- crates/hir-ty/src/tests/traits.rs | 92 ++++++++++++++++- crates/hir/src/diagnostics.rs | 14 +-- crates/hir/src/lib.rs | 38 +++---- .../src/handlers/incorrect_try_expr.rs | 37 ------- .../src/handlers/not_implemented.rs | 35 ------- crates/ide-diagnostics/src/lib.rs | 4 - crates/ide/src/hover/tests.rs | 22 +---- crates/test-utils/src/minicore.rs | 39 +------- 13 files changed, 125 insertions(+), 289 deletions(-) delete mode 100644 crates/ide-diagnostics/src/handlers/incorrect_try_expr.rs delete mode 100644 crates/ide-diagnostics/src/handlers/not_implemented.rs diff --git a/crates/hir-expand/src/mod_path.rs b/crates/hir-expand/src/mod_path.rs index 68413df420c..d7586d129b7 100644 --- a/crates/hir-expand/src/mod_path.rs +++ b/crates/hir-expand/src/mod_path.rs @@ -259,7 +259,6 @@ macro_rules! __known_path { (core::future::Future) => {}; (core::future::IntoFuture) => {}; (core::ops::Try) => {}; - (core::ops::FromResidual) => {}; ($path:path) => { compile_error!("Please register your known path in the path module") }; diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index 8a735b965ab..2679a1c3602 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -279,8 +279,6 @@ pub mod known { RangeToInclusive, RangeTo, Range, - Residual, - FromResidual, Neg, Not, None, diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 4315ccab6c1..31e56dec625 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -190,9 +190,7 @@ pub(crate) type InferResult = Result, TypeError>; pub enum InferenceDiagnostic { NoSuchField { expr: ExprId }, BreakOutsideOfLoop { expr: ExprId, is_break: bool }, - IncorrectTryTarget { expr: ExprId }, MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize }, - DoesNotImplement { expr: ExprId, trait_: TraitId, ty: Ty }, } /// A mismatch between an expected and an inferred type. @@ -907,6 +905,17 @@ impl<'a> InferenceContext<'a> { self.db.trait_data(trait_).associated_type_by_name(&name![Item]) } + fn resolve_ops_try_ok(&self) -> Option { + // FIXME resolve via lang_item once try v2 is stable + let path = path![core::ops::Try]; + let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; + let trait_data = self.db.trait_data(trait_); + trait_data + // FIXME remove once try v2 is stable + .associated_type_by_name(&name![Ok]) + .or_else(|| trait_data.associated_type_by_name(&name![Output])) + } + fn resolve_ops_neg_output(&self) -> Option { let trait_ = self.resolve_lang_item(name![neg])?.as_trait()?; self.db.trait_data(trait_).associated_type_by_name(&name![Output]) diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 59ab50d0717..f56108b26c4 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -19,24 +19,24 @@ use hir_def::{ resolver::resolver_for_expr, ConstParamId, FieldId, ItemContainerId, Lookup, }; -use hir_expand::{name, name::Name}; +use hir_expand::name::Name; use stdx::always; use syntax::ast::RangeOp; use crate::{ autoderef::{self, Autoderef}, consteval, - infer::{coerce::CoerceMany, find_continuable, path, BreakableKind}, + infer::{coerce::CoerceMany, find_continuable, BreakableKind}, lower::{ const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode, }, mapping::{from_chalk, ToChalk}, method_resolution::{self, lang_names_for_bin_op, VisibleFromModule}, primitive::{self, UintTy}, - static_lifetime, to_assoc_type_id, to_chalk_trait_id, + static_lifetime, to_chalk_trait_id, utils::{generics, Generics}, - AdtId, AliasEq, AliasTy, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, - ProjectionTy, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind, + AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar, + Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind, }; use super::{ @@ -564,29 +564,9 @@ impl<'a> InferenceContext<'a> { let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); self.resolve_associated_type(inner_ty, self.resolve_future_future_output()) } - &Expr::Try { expr } => { - let inner_ty = self.infer_expr_inner(expr, &Expectation::none()); - match self.resolve_try_impl_for(inner_ty.clone()) { - Some((_, Some((output, residual)))) => { - if let Some((_trait, false)) = - self.implements_from_residual(self.return_ty.clone(), residual) - { - self.push_diagnostic(InferenceDiagnostic::IncorrectTryTarget { - expr: tgt_expr, - }); - } - output - } - Some((trait_, None)) => { - self.push_diagnostic(InferenceDiagnostic::DoesNotImplement { - expr, - trait_, - ty: inner_ty, - }); - self.err_ty() - } - None => self.err_ty(), - } + Expr::Try { expr } => { + let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); + self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok()) } Expr::Cast { expr, type_ref } => { // FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary) @@ -1550,67 +1530,4 @@ impl<'a> InferenceContext<'a> { let ctx = self.breakables.pop().expect("breakable stack broken"); (ctx.may_break.then(|| ctx.coerce.complete()), res) } - - /// Check whether `ty` implements `FromResidual` - fn implements_from_residual(&mut self, ty: Ty, r: Ty) -> Option<(hir_def::TraitId, bool)> { - let from_residual_trait = self - .resolver - .resolve_known_trait(self.db.upcast(), &(super::path![core::ops::FromResidual]))?; - let r = GenericArgData::Ty(r).intern(Interner); - let b = TyBuilder::trait_ref(self.db, from_residual_trait); - if b.remaining() != 2 { - return Some((from_residual_trait, false)); - } - let trait_ref = b.push(ty).push(r).build(); - Some((from_residual_trait, self.table.try_obligation(trait_ref.cast(Interner)).is_some())) - } - - fn resolve_try_impl_for(&mut self, ty: Ty) -> Option<(hir_def::TraitId, Option<(Ty, Ty)>)> { - let path = path![core::ops::Try]; - let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; - - let trait_ref = TyBuilder::trait_ref(self.db, trait_).push(ty).build(); - let substitution = trait_ref.substitution.clone(); - self.push_obligation(trait_ref.clone().cast(Interner)); - - let trait_data = self.db.trait_data(trait_); - let output = trait_data.associated_type_by_name(&name![Output]); - let residual = trait_data.associated_type_by_name(&name![Residual]); - - let output_ty = match output { - Some(output) => { - let output_ty = self.table.new_type_var(); - let alias_eq = AliasEq { - alias: AliasTy::Projection(ProjectionTy { - associated_ty_id: to_assoc_type_id(output), - substitution: substitution.clone(), - }), - ty: output_ty.clone(), - }; - self.push_obligation(alias_eq.cast(Interner)); - output_ty - } - None => self.err_ty(), - }; - let residual_ty = match residual { - Some(residual) => { - let residual_ty = self.table.new_type_var(); - let alias_eq = AliasEq { - alias: AliasTy::Projection(ProjectionTy { - associated_ty_id: to_assoc_type_id(residual), - substitution, - }), - ty: residual_ty.clone(), - }; - self.push_obligation(alias_eq.cast(Interner)); - residual_ty - } - None => self.err_ty(), - }; - // FIXME: We are doing the work twice here I think? - Some(( - trait_, - self.table.try_obligation(trait_ref.cast(Interner)).map(|_| (output_ty, residual_ty)), - )) - } } diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 224dc21e94e..5998680dcd3 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -1111,24 +1111,6 @@ pub fn resolve_indexing_op( } None } -/// Returns the receiver type for the try branch trait call. -pub fn resolve_branch_op( - db: &dyn HirDatabase, - env: Arc, - ty: Canonical, - try_trait: TraitId, -) -> Option { - let mut table = InferenceTable::new(db, env.clone()); - let ty = table.instantiate_canonical(ty); - let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty); - for (ty, adj) in deref_chain.into_iter().zip(adj) { - let goal = generic_implements_goal(db, env.clone(), try_trait, &ty); - if db.trait_solve(env.krate, goal.cast(Interner)).is_some() { - return Some(adj); - } - } - None -} macro_rules! check_that { ($cond:expr) => { diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index b91172e3342..555b6972fb7 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -162,16 +162,98 @@ fn test() { ); } +#[test] +fn infer_try() { + check_types( + r#" +//- /main.rs crate:main deps:core +fn test() { + let r: Result = Result::Ok(1); + let v = r?; + v; +} //^ i32 + +//- /core.rs crate:core +pub mod ops { + pub trait Try { + type Ok; + type Error; + } +} + +pub mod result { + pub enum Result { + Ok(O), + Err(E) + } + + impl crate::ops::Try for Result { + type Ok = O; + type Error = E; + } +} + +pub mod prelude { + pub mod rust_2018 { + pub use crate::{result::*, ops::*}; + } +} +"#, + ); +} + #[test] fn infer_try_trait_v2() { check_types( r#" -//- minicore: try -fn test() -> core::ops::ControlFlow { - let r: core::ops::ControlFlow = core::ops::ControlFlow::Continue(1.0); +//- /main.rs crate:main deps:core +fn test() { + let r: Result = Result::Ok(1); let v = r?; - //^ f32 - r + v; +} //^ i32 + +//- /core.rs crate:core +mod ops { + mod try_trait { + pub trait Try: FromResidual { + type Output; + type Residual; + } + pub trait FromResidual::Residual> {} + } + + pub use self::try_trait::FromResidual; + pub use self::try_trait::Try; +} + +mod convert { + pub trait From {} + impl From for T {} +} + +pub mod result { + use crate::convert::From; + use crate::ops::{Try, FromResidual}; + + pub enum Infallible {} + pub enum Result { + Ok(O), + Err(E) + } + + impl Try for Result { + type Output = O; + type Error = Result; + } + + impl> FromResidual> for Result {} +} + +pub mod prelude { + pub mod rust_2018 { + pub use crate::result::*; + } } "#, ); diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 6c8b3088adc..c5dc60f1ec5 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -6,7 +6,7 @@ use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; use either::Either; -use hir_def::{path::ModPath, TraitId}; +use hir_def::path::ModPath; use hir_expand::{name::Name, HirFileId, InFile}; use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; @@ -33,7 +33,6 @@ diagnostics![ BreakOutsideOfLoop, InactiveCode, IncorrectCase, - IncorrectTryExpr, InvalidDeriveTarget, MacroError, MalformedDerive, @@ -41,7 +40,6 @@ diagnostics![ MissingFields, MissingMatchArms, MissingUnsafe, - NotImplemented, NoSuchField, ReplaceFilterMapNextWithFindMap, TypeMismatch, @@ -155,16 +153,6 @@ pub struct MismatchedArgCount { pub expected: usize, pub found: usize, } -#[derive(Debug)] -pub struct IncorrectTryExpr { - pub expr: InFile>, -} -#[derive(Debug)] -pub struct NotImplemented { - pub expr: InFile>, - pub trait_: TraitId, - pub ty: Type, -} #[derive(Debug)] pub struct MissingMatchArms { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index e6c5c6b5833..f5324208c9a 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -81,12 +81,11 @@ use crate::db::{DefDatabase, HirDatabase}; pub use crate::{ attrs::{HasAttrs, Namespace}, diagnostics::{ - AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, IncorrectTryExpr, - InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, MissingFields, - MissingMatchArms, MissingUnsafe, NoSuchField, NotImplemented, - ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro, - UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, UnresolvedModule, - UnresolvedProcMacro, + AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, InvalidDeriveTarget, + MacroError, MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms, + MissingUnsafe, NoSuchField, ReplaceFilterMapNextWithFindMap, TypeMismatch, + UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, + UnresolvedModule, UnresolvedProcMacro, }, has_source::HasSource, semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits}, @@ -1283,45 +1282,30 @@ impl DefWithBody { let infer = db.infer(self.into()); let source_map = Lazy::new(|| db.body_with_source_map(self.into()).1); for d in &infer.diagnostics { - match *d { + match d { hir_ty::InferenceDiagnostic::NoSuchField { expr } => { - let field = source_map.field_syntax(expr); + let field = source_map.field_syntax(*expr); acc.push(NoSuchField { field }.into()) } - hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => { + &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => { let expr = source_map .expr_syntax(expr) .expect("break outside of loop in synthetic syntax"); acc.push(BreakOutsideOfLoop { expr, is_break }.into()) } hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => { - match source_map.expr_syntax(call_expr) { + match source_map.expr_syntax(*call_expr) { Ok(source_ptr) => acc.push( MismatchedArgCount { call_expr: source_ptr, - expected: expected, - found: found, + expected: *expected, + found: *found, } .into(), ), Err(SyntheticSyntax) => (), } } - hir_ty::InferenceDiagnostic::IncorrectTryTarget { expr } => { - let expr = source_map.expr_syntax(expr).expect("try in synthetic syntax"); - acc.push(IncorrectTryExpr { expr }.into()) - } - hir_ty::InferenceDiagnostic::DoesNotImplement { expr, trait_, ref ty } => { - let expr = source_map.expr_syntax(expr).expect("try in synthetic syntax"); - acc.push( - NotImplemented { - expr, - trait_, - ty: Type::new(db, DefWithBodyId::from(self), ty.clone()), - } - .into(), - ) - } } } for (expr, mismatch) in infer.expr_type_mismatches() { diff --git a/crates/ide-diagnostics/src/handlers/incorrect_try_expr.rs b/crates/ide-diagnostics/src/handlers/incorrect_try_expr.rs deleted file mode 100644 index 085d8d32598..00000000000 --- a/crates/ide-diagnostics/src/handlers/incorrect_try_expr.rs +++ /dev/null @@ -1,37 +0,0 @@ -use hir::InFile; - -use crate::{Diagnostic, DiagnosticsContext}; - -// Diagnostic: incorrect-try-target -// -// This diagnostic is triggered if a question mark operator was used in a context where it is not applicable. -pub(crate) fn incorrect_try_expr( - ctx: &DiagnosticsContext<'_>, - d: &hir::IncorrectTryExpr, -) -> Diagnostic { - Diagnostic::new( - "incorrect-try-target", - format!("the return type of the containing function does not implement `FromResidual`"), - ctx.sema - .diagnostics_display_range(InFile::new(d.expr.file_id, d.expr.value.clone().into())) - .range, - ) -} - -#[cfg(test)] -mod tests { - use crate::tests::check_diagnostics; - - #[test] - fn try_ops_diag() { - check_diagnostics( - r#" -//- minicore: try -fn test() { - core::ops::ControlFlow::::Continue(1.0)?; - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the return type of the containing function does not implement `FromResidual` -} -"#, - ); - } -} diff --git a/crates/ide-diagnostics/src/handlers/not_implemented.rs b/crates/ide-diagnostics/src/handlers/not_implemented.rs deleted file mode 100644 index 3bf6a423229..00000000000 --- a/crates/ide-diagnostics/src/handlers/not_implemented.rs +++ /dev/null @@ -1,35 +0,0 @@ -use hir::{db::DefDatabase, HirDisplay}; - -use crate::{Diagnostic, DiagnosticsContext}; - -// Diagnostic: not-implemented -// -// This diagnostic is triggered if a type doesn't implement a necessary trait. -pub(crate) fn not_implemented(ctx: &DiagnosticsContext<'_>, d: &hir::NotImplemented) -> Diagnostic { - Diagnostic::new( - "not-implemented", - format!( - "the trait `{}` is not implemented for `{}`", - ctx.sema.db.trait_data(d.trait_).name, - d.ty.display(ctx.sema.db) - ), - ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range, - ) -} - -#[cfg(test)] -mod tests { - use crate::tests::check_diagnostics; - - #[test] - fn missing_try_impl() { - check_diagnostics( - r#" -//- minicore: try -fn main() { - ()?; -} //^^ error: the trait `Try` is not implemented for `()` -"#, - ) - } -} diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index 4577072149a..ae299f05841 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -29,7 +29,6 @@ mod handlers { pub(crate) mod break_outside_of_loop; pub(crate) mod inactive_code; pub(crate) mod incorrect_case; - pub(crate) mod incorrect_try_expr; pub(crate) mod invalid_derive_target; pub(crate) mod macro_error; pub(crate) mod malformed_derive; @@ -37,7 +36,6 @@ mod handlers { pub(crate) mod missing_fields; pub(crate) mod missing_match_arms; pub(crate) mod missing_unsafe; - pub(crate) mod not_implemented; pub(crate) mod no_such_field; pub(crate) mod replace_filter_map_next_with_find_map; pub(crate) mod type_mismatch; @@ -227,14 +225,12 @@ pub fn diagnostics( let d = match diag { AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d), AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d), - AnyDiagnostic::IncorrectTryExpr(d) => handlers::incorrect_try_expr::incorrect_try_expr(&ctx, &d), AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d), AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d), AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d), AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d), AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d), AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d), - AnyDiagnostic::NotImplemented(d) => handlers::not_implemented::not_implemented(&ctx, &d), AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d), AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d), AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d), diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 5cab017a58d..eb997e6fef8 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -4913,22 +4913,6 @@ fn foo() -> NotResult<(), Short> { ``` "#]], ); - check_hover_range( - r#" -//- minicore: try -use core::ops::ControlFlow; -fn foo() -> ControlFlow<()> { - $0ControlFlow::Break(())?$0; - ControlFlow::Continue(()) -} -"#, - expect![[r#" - ```text - Try Target Type: ControlFlow<(), {unknown}> - Propagated as: ControlFlow<(), ()> - ``` - "#]], - ); } #[test] @@ -4944,9 +4928,9 @@ fn foo() -> Option<()> { } "#, expect![[r#" - ```rust - i32 - ```"#]], + ```rust + as Try>::Output + ```"#]], ); } diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 59b1c147d7f..69d2e62b256 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -27,7 +27,6 @@ //! generator: pin //! hash: //! index: sized -//! infallible: //! iterator: option //! iterators: iterator, fn //! option: @@ -37,7 +36,7 @@ //! result: //! sized: //! slice: -//! try: infallible +//! try: //! unsize: sized pub mod marker { @@ -151,9 +150,6 @@ pub mod convert { fn as_ref(&self) -> &T; } // endregion:as_ref - // region:infallible - pub enum Infallible {} - // endregion:infallible } pub mod ops { @@ -330,7 +326,7 @@ pub mod ops { Continue(C), Break(B), } - pub trait FromResidual::Residual> { + pub trait FromResidual { #[lang = "from_residual"] fn from_residual(residual: R) -> Self; } @@ -346,13 +342,13 @@ pub mod ops { impl Try for ControlFlow { type Output = C; - type Residual = ControlFlow; + type Residual = ControlFlow; fn from_output(output: Self::Output) -> Self {} fn branch(self) -> ControlFlow {} } impl FromResidual for ControlFlow { - fn from_residual(residual: ControlFlow) -> Self {} + fn from_residual(residual: ControlFlow) -> Self {} } } pub use self::try_::{ControlFlow, FromResidual, Try}; @@ -473,33 +469,6 @@ pub mod option { } } } - // region:try - impl crate::ops::Try for Option { - type Output = T; - type Residual = Option; - - #[inline] - fn from_output(output: Self::Output) -> Self { - Some(output) - } - - #[inline] - fn branch(self) -> crate::ops::ControlFlow { - match self { - Some(v) => crate::ops::ControlFlow::Continue(v), - None => crate::ops::ControlFlow::Break(None), - } - } - } - impl crate::ops::FromResidual for Option { - #[inline] - fn from_residual(residual: Option) -> Self { - match residual { - None => None, - } - } - } - // endregion:try } // endregion:option