diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index f4bfec24e3b1b..fd1375d6e7855 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1939,7 +1939,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// // If there is an enclosing `try {...}`: /// break 'catch_target Residual::into_try_type(residual), /// // Otherwise: - /// return Try::from_residual(residual), + /// return TryFromBreak::from_break(residual), /// } /// ``` fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir> { @@ -1962,7 +1962,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr_call_lang_item_fn( unstable_span, - LangItem::TryTraitBranch, + LangItem::TryOperatorBranch, arena_vec![self; sub_expr], ) }; @@ -1981,22 +1981,17 @@ impl<'hir> LoweringContext<'_, 'hir> { // `ControlFlow::Break(residual) => // #[allow(unreachable_code)] - // return Try::from_residual(residual),` + // return TryFromBreak::from_break(residual),` let break_arm = { let residual_ident = Ident::with_dummy_span(sym::residual); let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident); let residual_expr = self.expr_ident_mut(try_span, residual_ident, residual_local_nid); - let (constructor_item, target_id) = match self.try_block_scope { - TryBlockScope::Function => { - (LangItem::TryTraitFromResidual, Err(hir::LoopIdError::OutsideLoopScope)) - } - TryBlockScope::Homogeneous(block_id) => { - (LangItem::ResidualIntoTryType, Ok(block_id)) - } - TryBlockScope::Heterogeneous(block_id) => { - (LangItem::TryTraitFromResidual, Ok(block_id)) + let constructor_item = match self.try_block_scope { + TryBlockScope::Function | TryBlockScope::Heterogeneous(_) => { + LangItem::IntoTryHeterogeneous } + TryBlockScope::Homogeneous(_) => LangItem::IntoTryHomogeneous, }; let from_residual_expr = self.wrap_in_try_constructor( constructor_item, @@ -2004,17 +1999,20 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(residual_expr), unstable_span, ); - let ret_expr = if target_id.is_ok() { - self.arena.alloc(self.expr( - try_span, - hir::ExprKind::Break( - hir::Destination { label: None, target_id }, - Some(from_residual_expr), - ), - )) - } else { - let ret_expr = self.checked_return(Some(from_residual_expr)); - self.arena.alloc(self.expr(try_span, ret_expr)) + let ret_expr = match self.try_block_scope { + TryBlockScope::Function => { + let ret_expr = self.checked_return(Some(from_residual_expr)); + self.arena.alloc(self.expr(try_span, ret_expr)) + } + TryBlockScope::Homogeneous(block_id) | TryBlockScope::Heterogeneous(block_id) => { + self.arena.alloc(self.expr( + try_span, + hir::ExprKind::Break( + hir::Destination { label: None, target_id: Ok(block_id) }, + Some(from_residual_expr), + ), + )) + } }; self.lower_attrs(ret_expr.hir_id, &attrs, span, Target::Expression); @@ -2032,12 +2030,12 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Desugar `ExprKind::Yeet` from: `do yeet ` into: /// ```ignore(illustrative) /// // If there is an enclosing `try {...}`: - /// break 'catch_target FromResidual::from_residual(Yeet(residual)); + /// break 'catch_target TryFromBreak::from_break(Yeet(residual)); /// // Otherwise: - /// return FromResidual::from_residual(Yeet(residual)); + /// return TryFromBreak::from_break(Yeet(residual)); /// ``` /// But to simplify this, there's a `from_yeet` lang item function which - /// handles the combined `FromResidual::from_residual(Yeet(residual))`. + /// handles the combined `TryFromBreak::from_break(Yeet(residual))`. fn lower_expr_yeet(&mut self, span: Span, sub_expr: Option<&Expr>) -> hir::ExprKind<'hir> { // The expression (if present) or `()` otherwise. let (yeeted_span, yeeted_expr) = if let Some(sub_expr) = sub_expr { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b6d1017665ec6..63cdeb599255f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -334,7 +334,7 @@ macro_rules! allow { allow! { ALLOW_CONTRACTS: [sym::contracts_internals]; - ALLOW_TRY_TRAIT: [sym::try_trait_v2, sym::try_trait_v2_residual, sym::yeet_desugar_details]; + ALLOW_TRY_TRAIT: [sym::try_internals, sym::try_trait_v2, sym::yeet_desugar_details]; ALLOW_PATTERN_TYPE: [sym::pattern_types, sym::pattern_type_range_trait]; ALLOW_GEN_FUTURE: [sym::gen_future]; ALLOW_GEN_FUTURE_WITH_ASYNC_FN_TRACK_CALLER: [sym::gen_future, sym::closure_track_caller]; diff --git a/compiler/rustc_attr_ir/src/diagnostic.rs b/compiler/rustc_attr_ir/src/diagnostic.rs index ead8fbb89dfbd..c43fd89c7c01b 100644 --- a/compiler/rustc_attr_ir/src/diagnostic.rs +++ b/compiler/rustc_attr_ir/src/diagnostic.rs @@ -184,12 +184,12 @@ impl FormatString { /// on(all(from_desugaring = "QuestionMark"), /// message = "the `?` operator can only be used in {ItemContext} \ /// that returns `Result` or `Option` \ -/// (or another type that implements `{FromResidual}`)", +/// (or another type that implements `{TryFromBreak}`)", /// label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", /// parent_label = "this function should return `Result` or `Option` to accept `?`" /// ), /// )] -/// pub trait FromResidual::Residual> { +/// pub trait TryFromBreak::Break> { /// ... /// } /// @@ -203,8 +203,8 @@ impl FormatString { /// /// ```rust,ignore (just an example) /// FormatArgs { -/// this: "FromResidual", -/// this_resolved: "FromResidual>", +/// this: "TryFromBreak", +/// this_resolved: "TryFromBreak>", /// item_context: "an async function", /// generic_args: [("Self", "u32"), ("R", "Option")], /// } @@ -419,12 +419,12 @@ pub enum LitOrArg { /// on(all(from_desugaring = "QuestionMark"), /// message = "the `?` operator can only be used in {ItemContext} \ /// that returns `Result` or `Option` \ -/// (or another type that implements `{FromResidual}`)", +/// (or another type that implements `{TryFromBreak}`)", /// label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", /// parent_label = "this function should return `Result` or `Option` to accept `?`" /// ), /// )] -/// pub trait FromResidual::Residual> { +/// pub trait TryFromBreak::Break> { /// ... /// } /// diff --git a/compiler/rustc_attr_ir/src/lang_items.rs b/compiler/rustc_attr_ir/src/lang_items.rs index 60890f7799290..9c308f8264ca5 100644 --- a/compiler/rustc_attr_ir/src/lang_items.rs +++ b/compiler/rustc_attr_ir/src/lang_items.rs @@ -375,11 +375,11 @@ language_item_table! { SliceLen, sym::slice_len_fn, slice_len_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None; // Language items from AST lowering - TryTraitFromResidual, sym::from_residual, from_residual_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + IntoTryHeterogeneous, sym::into_try_heterogeneous, into_try_heterogeneous_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None; + IntoTryHomogeneous, sym::into_try_homogeneous, into_try_homogeneous_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None; + TryOperatorBranch, sym::try_operator_branch, try_operator_branch_fn, Target::Fn, GenericRequirement::None; TryTraitFromOutput, sym::from_output, from_output_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; - TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; TryTraitFromYeet, sym::from_yeet, from_yeet_fn, Target::Fn, GenericRequirement::None; - ResidualIntoTryType, sym::into_try_type, into_try_type_fn, Target::Fn, GenericRequirement::None; CoercePointeeValidated, sym::coerce_pointee_validated, coerce_pointee_validated_trait, Target::Trait, GenericRequirement::Exact(0); diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 2bc361968a761..fb0d30d3abde8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -763,7 +763,8 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { } UseSpans::PatUse(span) | UseSpans::OtherUse(span) - | UseSpans::FnSelfUse { var_span: span, .. } => { + | UseSpans::FnSelfUse { var_span: span, .. } + | UseSpans::QuestionMarkUse(span) => { let block = &self.body.basic_blocks[location.block]; let kind = if let Some(&Statement { diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index cb60a97eea053..71253a3e16bc5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -764,6 +764,7 @@ pub(super) enum UseSpans<'tcx> { }, /// This access is caused by a `match` or `if let` pattern. PatUse(Span), + QuestionMarkUse(Span), /// This access has a single span associated to it: common case. OtherUse(Span), } @@ -773,7 +774,8 @@ impl UseSpans<'_> { match self { UseSpans::ClosureUse { args_span: span, .. } | UseSpans::PatUse(span) - | UseSpans::OtherUse(span) => span, + | UseSpans::OtherUse(span) + | UseSpans::QuestionMarkUse(span) => span, UseSpans::FnSelfUse { var_span, .. } => var_span, } } @@ -783,7 +785,8 @@ impl UseSpans<'_> { match self { UseSpans::ClosureUse { path_span: span, .. } | UseSpans::PatUse(span) - | UseSpans::OtherUse(span) => span, + | UseSpans::OtherUse(span) + | UseSpans::QuestionMarkUse(span) => span, UseSpans::FnSelfUse { var_span, .. } => var_span, } } @@ -793,7 +796,8 @@ impl UseSpans<'_> { match self { UseSpans::ClosureUse { capture_kind_span: span, .. } | UseSpans::PatUse(span) - | UseSpans::OtherUse(span) => span, + | UseSpans::OtherUse(span) + | UseSpans::QuestionMarkUse(span) => span, UseSpans::FnSelfUse { var_span, .. } => var_span, } } @@ -902,9 +906,10 @@ impl UseSpans<'_> { F: FnOnce() -> Self, { match self { - closure @ UseSpans::ClosureUse { .. } => closure, + UseSpans::ClosureUse { .. } + | UseSpans::FnSelfUse { .. } + | UseSpans::QuestionMarkUse(_) => self, UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(), - fn_self @ UseSpans::FnSelfUse { .. } => fn_self, } } } @@ -1082,34 +1087,43 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { debug!("move_spans: target_temp = {:?}", target_temp); - if let Some(Terminator { - kind: TerminatorKind::Call { fn_span, call_source, .. }, .. - }) = &self.body[location.block].terminator + if let Some(terminator) = &self.body[location.block].terminator + && let TerminatorKind::Call { + ref args, + fn_span, + func: Operand::Constant(ref func), + call_source, + .. + } = terminator.kind { - let Some((method_did, method_args)) = + if let Some((method_did, method_args)) = find_self_call(self.infcx.tcx, self.body, target_temp, location.block) - else { - return normal_ret; - }; + { + let kind = call_kind( + self.infcx.tcx, + self.infcx.typing_env(self.infcx.param_env), + method_did, + method_args, + fn_span, + call_source.from_hir_call(), + self.infcx.tcx.fn_arg_idents(method_did)[0], + ); - let kind = call_kind( - self.infcx.tcx, - self.infcx.typing_env(self.infcx.param_env), - method_did, - method_args, - *fn_span, - call_source.from_hir_call(), - self.infcx.tcx.fn_arg_idents(method_did)[0], - ); - - return FnSelfUse { - var_span: stmt.source_info.span, - fn_call_span: *fn_span, - fn_span: self.infcx.tcx.def_span(method_did), - kind, - }; + return FnSelfUse { + var_span: stmt.source_info.span, + fn_call_span: fn_span, + fn_span: self.infcx.tcx.def_span(method_did), + kind, + }; + } else if let ty::FnDef(def_id, _) = *func.ty().kind() + && self.infcx.tcx.is_lang_item(def_id, LangItem::TryOperatorBranch) + && let [arg] = args + && let Operand::Move(arg_place) | Operand::Copy(arg_place) = arg.node + && arg_place.as_local() == Some(target_temp) + { + return QuestionMarkUse(fn_span); + } } - normal_ret } @@ -1471,14 +1485,6 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { is_loop_message, }); } - Some((CallDesugaringKind::QuestionBranch, _)) => { - err.subdiagnostic(CaptureReasonLabel::QuestionMark { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }); - } _ => { err.subdiagnostic(CaptureReasonLabel::MethodCall { fn_call_span, @@ -1509,113 +1515,26 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { }); has_sugg = true; } - if let Some(clone_trait) = tcx.lang_items().clone_trait() { - // Check whether the deref is from a custom Deref impl - // (e.g. Rc, Box) or a built-in reference deref. - // For built-in derefs with Clone fully satisfied, we skip - // the UFCS suggestion here and let `suggest_cloning` - // downstream emit a simpler `.clone()` suggestion instead. - let has_overloaded_deref = - moved_place.iter_projections().any(|(place, elem)| { - matches!(elem, ProjectionElem::Deref) - && matches!( - self.borrowed_content_source(place), - BorrowedContentSource::OverloadedDeref(_) - | BorrowedContentSource::OverloadedIndex(_) - ) - }); - - let has_deref = moved_place - .iter_projections() - .any(|(_, elem)| matches!(elem, ProjectionElem::Deref)); - - let sugg = if has_deref { - let (start, end) = if let Some(expr) = self.find_expr(move_span) - && let Some(_) = self.clone_on_reference(expr) - && let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind - { - (move_span.shrink_to_lo(), move_span.with_lo(rcvr.span.hi())) - } else { - (move_span.shrink_to_lo(), move_span.shrink_to_hi()) - }; - vec![ - // We use the fully-qualified path because `.clone()` can - // sometimes choose `<&T as Clone>` instead of `` - // when going through auto-deref, so this ensures that doesn't - // happen, causing suggestions for `.clone().clone()`. - (start, format!("<{ty} as Clone>::clone(&")), - (end, ")".to_string()), - ] - } else { - vec![(move_span.shrink_to_hi(), ".clone()".to_string())] - }; - if let Some(errors) = self.infcx.type_implements_trait_shallow( - clone_trait, - ty, - self.infcx.param_env, - ) && !has_sugg - { - let skip_for_simple_clone = - has_deref && !has_overloaded_deref && errors.no_errors(); - if !skip_for_simple_clone { - let msg = match errors.as_slice() { - [] => "you can `clone` the value and consume it, but \ - this might not be your desired behavior" - .to_string(), - [error] => { - format!( - "you could `clone` the value and consume it, if \ - the `{}` trait bound could be satisfied", - error.obligation.predicate, - ) - } - _ => { - format!( - "you could `clone` the value and consume it, if \ - the following trait bounds could be satisfied: \ - {}", - listify( - errors.as_slice(), - |e: &FulfillmentError<'tcx>| format!( - "`{}`", - e.obligation.predicate - ) - ) - .unwrap(), - ) - } - }; - err.multipart_suggestion( - msg, - sugg, - Applicability::MaybeIncorrect, - ); - - suggested_cloning = errors.no_errors(); - - for error in errors { - if let FulfillmentErrorCode::Select( - SelectionError::Unimplemented, - ) = error.code - && let ty::PredicateKind::Clause(ty::ClauseKind::Trait( - pred, - )) = error.obligation.predicate.kind().skip_binder() - { - self.infcx.err_ctxt().suggest_derive( - &error.obligation, - err, - error.obligation.predicate.kind().rebind(pred), - ); - } - } - } - } + if !has_sugg { + suggested_cloning = self.suggest_clone(err, moved_place, move_span) } } } // Other desugarings takes &self, which cannot cause a move _ => {} } + } else if let UseSpans::QuestionMarkUse(span) = move_spans { + let place_name = self + .describe_place(moved_place.as_ref()) + .map(|n| format!("`{n}`")) + .unwrap_or_else(|| "value".to_owned()); + err.subdiagnostic(CaptureReasonLabel::QuestionMark { + span, + place_name: &place_name, + is_partial, + is_loop_message, + }); + suggested_cloning = self.suggest_clone(err, moved_place, move_span) } else { if move_span != span || is_loop_message { err.subdiagnostic(CaptureReasonLabel::MovedHere { @@ -1645,6 +1564,104 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { pub(crate) fn local_excluded_from_unused_mut_lint(&self, index: Local) -> bool { self.local_name(index).is_none_or(|name| name.as_str().starts_with('_')) } + + fn suggest_clone(&self, err: &mut Diag<'_>, moved_place: Place<'tcx>, move_span: Span) -> bool { + let tcx = self.infcx.tcx; + let Some(clone_trait) = tcx.lang_items().clone_trait() else { + return false; + }; + // Check whether the deref is from a custom Deref impl + // (e.g. Rc, Box) or a built-in reference deref. + // For built-in derefs with Clone fully satisfied, we skip + // the UFCS suggestion here and let `suggest_cloning` + // downstream emit a simpler `.clone()` suggestion instead. + let has_overloaded_deref = moved_place.iter_projections().any(|(place, elem)| { + matches!(elem, ProjectionElem::Deref) + && matches!( + self.borrowed_content_source(place), + BorrowedContentSource::OverloadedDeref(_) + | BorrowedContentSource::OverloadedIndex(_) + ) + }); + + let has_deref = + moved_place.iter_projections().any(|(_, elem)| matches!(elem, ProjectionElem::Deref)); + let ty = moved_place.ty(self.body, tcx).ty; + + let sugg = if has_deref { + let (start, end) = if let Some(expr) = self.find_expr(move_span) + && let Some(_) = self.clone_on_reference(expr) + && let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind + { + (move_span.shrink_to_lo(), move_span.with_lo(rcvr.span.hi())) + } else { + (move_span.shrink_to_lo(), move_span.shrink_to_hi()) + }; + vec![ + // We use the fully-qualified path because `.clone()` can + // sometimes choose `<&T as Clone>` instead of `` + // when going through auto-deref, so this ensures that doesn't + // happen, causing suggestions for `.clone().clone()`. + (start, format!("<{ty} as Clone>::clone(&")), + (end, ")".to_string()), + ] + } else { + vec![(move_span.shrink_to_hi(), ".clone()".to_string())] + }; + let Some(errors) = + self.infcx.type_implements_trait_shallow(clone_trait, ty, self.infcx.param_env) + else { + return false; + }; + let skip_for_simple_clone = has_deref && !has_overloaded_deref && errors.no_errors(); + if skip_for_simple_clone { + return false; + } + let msg = match errors.as_slice() { + [] => "you can `clone` the value and consume it, but \ + this might not be your desired behavior" + .to_string(), + [error] => { + format!( + "you could `clone` the value and consume it, if \ + the `{}` trait bound could be satisfied", + error.obligation.predicate, + ) + } + _ => { + format!( + "you could `clone` the value and consume it, if \ + the following trait bounds could be satisfied: \ + {}", + listify(errors.as_slice(), |e: &FulfillmentError<'tcx>| format!( + "`{}`", + e.obligation.predicate + )) + .unwrap(), + ) + } + }; + err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect); + + if errors.no_errors() { + return false; + } + + for error in errors { + if let FulfillmentErrorCode::Select(SelectionError::Unimplemented) = error.code + && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = + error.obligation.predicate.kind().skip_binder() + { + self.infcx.err_ctxt().suggest_derive( + &error.obligation, + err, + error.obligation.predicate.kind().rebind(pred), + ); + } + } + + true + } } const LIMITATION_NOTE: DiagMessage = diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 8935aed1e7e00..d1980ab60e497 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -400,7 +400,7 @@ pub(crate) enum CaptureReasonLabel<'a> { )] QuestionMark { #[primary_span] - fn_call_span: Span, + span: Span, place_name: &'a str, is_partial: bool, is_loop_message: bool, diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 192bb8556a75d..45e24f507034b 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::impls::{MaybeStorageLive, always_storage_live_locals}; -use rustc_span::{Span, Symbol, span_bug, sym}; +use rustc_span::{DesugaringKind, Span, Symbol, span_bug, sym}; use rustc_trait_selection::traits::{ Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt, }; @@ -500,6 +500,10 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { feature_enabled, safe_to_expose_on_stable: callee_safe_to_expose_on_stable, is_function_call: self.tcx.def_kind(def_id) != DefKind::Trait, + is_try: (self.tcx.is_lang_item(def_id, LangItem::IntoTryHeterogeneous) + || self.tcx.is_lang_item(def_id, LangItem::IntoTryHomogeneous) + || self.tcx.is_lang_item(def_id, LangItem::TryOperatorBranch)) + && self.span.is_desugaring(DesugaringKind::QuestionMark), }); } } diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index ace12201abf02..c4147eef6fb04 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -458,6 +458,8 @@ pub(crate) struct CallUnstable { pub safe_to_expose_on_stable: bool, /// true if `def_id` is the function we are calling, false if `def_id` is an unstable trait. pub is_function_call: bool, + /// true if this is a function call from `?` desugaring + pub is_try: bool, } impl<'tcx> NonConstOp<'tcx> for CallUnstable { @@ -473,10 +475,14 @@ impl<'tcx> NonConstOp<'tcx> for CallUnstable { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { assert!(!self.feature_enabled); let mut err = if self.is_function_call { - ccx.dcx().create_err(diagnostics::UnstableConstFn { - span, - def_path: ccx.tcx.def_path_str(self.def_id), - }) + if self.is_try { + ccx.dcx().create_err(diagnostics::UnstableConstTry { span }) + } else { + ccx.dcx().create_err(diagnostics::UnstableConstFn { + span, + def_path: ccx.tcx.def_path_str(self.def_id), + }) + } } else { ccx.dcx().create_err(diagnostics::UnstableConstTrait { span, diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 1cb6a8aed947d..fff2843c56e78 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -88,9 +88,9 @@ impl fmt::Display for ConstEvalErrKind { impl MachineStopType for ConstEvalErrKind {} /// The errors become [`InterpErrorKind::MachineStop`] when being raised. -impl<'tcx> Into> for ConstEvalErrKind { - fn into(self) -> InterpErrorInfo<'tcx> { - err_machine_stop!(self).into() +impl<'tcx> From for InterpErrorInfo<'tcx> { + fn from(kind: ConstEvalErrKind) -> InterpErrorInfo<'tcx> { + err_machine_stop!(kind).into() } } diff --git a/compiler/rustc_const_eval/src/diagnostics.rs b/compiler/rustc_const_eval/src/diagnostics.rs index 995356fd3b488..2a222b75d614c 100644 --- a/compiler/rustc_const_eval/src/diagnostics.rs +++ b/compiler/rustc_const_eval/src/diagnostics.rs @@ -162,6 +162,13 @@ pub(crate) struct UnstableConstTrait { pub def_path: String, } +#[derive(Diagnostic)] +#[diag("`?` is not yet stable in const contexts")] +pub(crate) struct UnstableConstTry { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag("`{$name}` is not yet stable as a const intrinsic")] pub(crate) struct UnstableIntrinsic { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 9f0d00d5274fa..0330add0d33b9 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -579,7 +579,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME it's a try block, not a question mark Some(ObligationCauseCode::QuestionMark) } - LangItem::TryTraitBranch | LangItem::TryTraitFromResidual + LangItem::IntoTryHeterogeneous + if expr.span.is_desugaring(DesugaringKind::QuestionMark) => + { + Some(ObligationCauseCode::QuestionMarkIntoTry) + } + LangItem::TryOperatorBranch if expr.span.is_desugaring(DesugaringKind::QuestionMark) => { Some(ObligationCauseCode::QuestionMark) diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 695eca6225858..fb683b92710d7 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -28,6 +28,8 @@ #![allow(internal_features)] #![allow(rustc::direct_use_of_rustc_type_ir)] #![cfg_attr(bootstrap, feature(debug_closure_helpers))] +#![cfg_attr(bootstrap, feature(try_trait_v2_residual))] +#![cfg_attr(bootstrap, feature(try_trait_v2_yeet))] #![cfg_attr(doc, feature(intra_doc_pointers))] #![feature(allocator_ext)] #![feature(associated_type_defaults)] @@ -52,8 +54,6 @@ #![feature(trait_alias)] #![feature(try_blocks)] #![feature(try_trait_v2)] -#![feature(try_trait_v2_residual)] -#![feature(try_trait_v2_yeet)] #![feature(type_alias_impl_trait)] #![feature(variant_count)] #![feature(yeet_expr)] diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 049e1ec22e547..1825e7d358f90 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,7 +1,9 @@ use std::any::Any; use std::backtrace::Backtrace; use std::borrow::Cow; -use std::{convert, fmt, mem, ops}; +#[cfg(bootstrap)] +use std::convert; +use std::{fmt, mem, ops}; use either::Either; use rustc_abi::{Align, Size, VariantIdx}; @@ -945,14 +947,30 @@ pub struct InterpResult<'tcx, T = ()> { } impl<'tcx, T> ops::Try for InterpResult<'tcx, T> { + #[cfg(not(bootstrap))] + type Kind = std::result::TryResult; + type Output = T; + #[cfg(bootstrap)] type Residual = InterpResult<'tcx, convert::Infallible>; + #[cfg(not(bootstrap))] + type Break = InterpErrorInfo<'tcx>; #[inline] fn from_output(output: Self::Output) -> Self { InterpResult::new(Ok(output)) } + #[cfg(not(bootstrap))] + #[inline] + fn branch(self) -> ops::ControlFlow { + match self.disarm() { + Ok(v) => ops::ControlFlow::Continue(v), + Err(e) => ops::ControlFlow::Break(e), + } + } + + #[cfg(bootstrap)] #[inline] fn branch(self) -> ops::ControlFlow { match self.disarm() { @@ -962,10 +980,17 @@ impl<'tcx, T> ops::Try for InterpResult<'tcx, T> { } } +#[cfg(bootstrap)] impl<'tcx, T> ops::Residual for InterpResult<'tcx, convert::Infallible> { type TryType = InterpResult<'tcx, T>; } +#[cfg(not(bootstrap))] +impl<'tcx, T, U> ops::TryAs for InterpResult<'tcx, T> { + type Try = InterpResult<'tcx, U>; +} + +#[cfg(bootstrap)] impl<'tcx, T> ops::FromResidual for InterpResult<'tcx, T> { #[inline] #[track_caller] @@ -976,7 +1001,17 @@ impl<'tcx, T> ops::FromResidual for InterpResult<'tcx, T> { } } +#[cfg(not(bootstrap))] +impl<'tcx, T, E: Into>> ops::TryFromBreak for InterpResult<'tcx, T> { + #[inline] + #[track_caller] + fn from_break(e: E) -> Self { + Self::new(Err(e.into())) + } +} + // Allow `yeet`ing `InterpError` in functions returning `InterpResult_`. +#[cfg(bootstrap)] impl<'tcx, T> ops::FromResidual>> for InterpResult<'tcx, T> { #[inline] fn from_residual(ops::Yeet(e): ops::Yeet>) -> Self { @@ -986,6 +1021,7 @@ impl<'tcx, T> ops::FromResidual>> for InterpResu // Allow `?` on `Result<_, InterpError>` in functions returning `InterpResult_`. // This is useful e.g. for `option.ok_or_else(|| err_ub!(...))`. +#[cfg(bootstrap)] impl<'tcx, T, E: Into>> ops::FromResidual> for InterpResult<'tcx, T> { diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 493f6989f342c..4365fd6f341bb 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -377,6 +377,8 @@ pub enum ObligationCauseCode<'tcx> { ForLoopIterator(HirId), QuestionMark, + // todo rename QuestionMark too? + QuestionMarkIntoTry, /// Well-formed checking. If a `WellFormedLoc` is provided, /// then it will be used to perform HIR-based wf checking diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index fa59c1c54ee89..83815548a7af0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -236,7 +236,6 @@ symbols! { Found, From, FromIterator, - FromResidual, GlobalAlloc, Hash, HashMap, @@ -352,7 +351,9 @@ symbols! { TryCaptureGeneric, TryCapturePrintable, TryFrom, + TryFromBreak, TryInto, + TryResult, Tuple, Ty, TyCtxt, @@ -1054,10 +1055,10 @@ symbols! { frem_algebraic, frem_fast, from, + from_break, from_desugaring, from_iter, from_output, - from_residual, from_size_align_unchecked, from_size_alignment_unchecked, from_str, @@ -1183,6 +1184,8 @@ symbols! { into_async_iter_into_iter, into_future, into_iter, + into_try_heterogeneous, + into_try_homogeneous, into_try_type, intra_doc_pointers, intrinsics, @@ -2203,9 +2206,10 @@ symbols! { try_blocks_heterogeneous, try_capture, try_from, + try_internals, try_into, + try_operator_branch, try_trait_v2, - try_trait_v2_residual, try_update, tt, tuple, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs index 4142febc7844f..8f4551190ee52 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs @@ -23,7 +23,7 @@ pub enum CallDesugaringKind { ForLoopNext, /// x? calls x.branch() QuestionBranch, - /// x? calls type_of(x)::from_residual() + /// x? calls type_of(x)::from_break() QuestionFromResidual, /// try { ..; x } calls type_of(x)::from_output(x) TryBlockFromOutput, @@ -52,7 +52,7 @@ impl CallDesugaringKind { Self::QuestionBranch | Self::TryBlockFromOutput => { tcx.require_lang_item(LangItem::Try, DUMMY_SP) } - Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(), + Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::TryFromBreak).unwrap(), Self::Await => tcx.get_diagnostic_item(sym::IntoFuture).unwrap(), } } @@ -160,10 +160,10 @@ pub fn call_kind<'tcx>( { Some((CallDesugaringKind::ForLoopNext, method_args.type_at(0))) } else if fn_call_span.desugaring_kind() == Some(DesugaringKind::QuestionMark) { - if tcx.is_lang_item(method_did, LangItem::TryTraitBranch) { + if tcx.is_lang_item(method_did, LangItem::TryOperatorBranch) { Some((CallDesugaringKind::QuestionBranch, method_args.type_at(0))) - } else if tcx.is_lang_item(method_did, LangItem::TryTraitFromResidual) { - Some((CallDesugaringKind::QuestionFromResidual, method_args.type_at(0))) + } else if tcx.is_lang_item(method_did, LangItem::IntoTryHeterogeneous) { + Some((CallDesugaringKind::QuestionFromResidual, method_args.type_at(1))) } else { None } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 3b21c5e5f19ba..cef55b9954e5f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -179,6 +179,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let Err(guar) = self.fn_arg_obligation(&obligation) { return guar; } + + // todo what if return type is not Try? + if matches!( + root_obligation.cause.code().peel_derives(), + ObligationCauseCode::QuestionMarkIntoTry, + ) && self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::Try) + { + // Silence Try error on `TryOperatorBreak` since it is already enforced + // on `Try::branch`. + return self.dcx().span_delayed_bug(span, "redundant Try error"); + }; + let (post_message, pre_message, type_def) = self .get_parent_trait_ref(obligation.cause.code()) .map(|(t, s)| { @@ -210,12 +222,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }); let is_try_conversion = self.is_try_conversion(span, main_trait_predicate.def_id()); - let is_question_mark = matches!( + let is_question_mark_into_try = matches!( root_obligation.cause.code().peel_derives(), - ObligationCauseCode::QuestionMark, + ObligationCauseCode::QuestionMarkIntoTry, ) && !(self .tcx - .is_diagnostic_item(sym::FromResidual, main_trait_predicate.def_id()) + .is_diagnostic_item(sym::TryFromBreak, main_trait_predicate.def_id()) || self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::Try)); let is_unsize = self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Unsize); @@ -232,7 +244,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { format!("`?` couldn't convert the error to `{ty}`"), vec![question_mark_message.to_owned()], ) - } else if is_question_mark { + } else if is_question_mark_into_try { let main_trait_predicate = self.tcx.short_string(main_trait_predicate, &mut long_ty_file); // Similar to the case above, but in this case the conversion is for a @@ -310,7 +322,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut suggested = false; let mut noted_missing_impl = false; - if is_try_conversion || is_question_mark { + if is_try_conversion || is_question_mark_into_try { (suggested, noted_missing_impl) = self.try_conversion_context( &obligation, main_trait_predicate, @@ -334,7 +346,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ret_span, format!("expected `{ty}` because of this"), ); - } else if is_question_mark { + } else if is_question_mark_into_try { let main_trait_predicate = self.tcx.short_string(main_trait_predicate, err.long_ty_path()); err.span_label( @@ -398,8 +410,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // When the self type is a type param We don't need to "the trait // `std::marker::Sized` is not implemented for `T`" as we will point // at the type param with a label to suggest constraining it. - && !self.tcx.is_diagnostic_item(sym::FromResidual, leaf_trait_predicate.def_id()) - // Don't say "the trait `FromResidual>` is + && !self.tcx.is_diagnostic_item(sym::TryFromBreak, leaf_trait_predicate.def_id()) + // Don't say "the trait `TryFromBreak>` is // not implemented for `Result`". { // We do this just so that the JSON output's `help` position is the @@ -1198,7 +1210,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let Some(typeck) = &self.typeck_results else { return (false, false); }; - let ObligationCauseCode::QuestionMark = obligation.cause.code().peel_derives() else { + let ObligationCauseCode::QuestionMarkIntoTry = obligation.cause.code().peel_derives() + else { return (false, false); }; let self_ty = trait_pred.skip_binder().self_ty(); @@ -2418,7 +2431,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { candidates = specific_candidates; } if let &[(cand, def_id)] = &candidates[..] { - if self.tcx.is_diagnostic_item(sym::FromResidual, cand.def_id) + if self.tcx.is_diagnostic_item(sym::TryFromBreak, cand.def_id) && !self.tcx.features().enabled(sym::try_trait_v2) { return false; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 76755eb481db7..817c670f8a7d4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3911,6 +3911,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ObligationCauseCode::AwaitableExpr(_) | ObligationCauseCode::ForLoopIterator(_) | ObligationCauseCode::QuestionMark + | ObligationCauseCode::QuestionMarkIntoTry | ObligationCauseCode::CheckAssociatedTypeBounds { .. } | ObligationCauseCode::LetElse | ObligationCauseCode::UnOp { .. } @@ -4608,11 +4609,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut parent_trait_pred = self.deeply_resolve_ignoring_regions(data.derived.parent_trait_pred); let parent_def_id = parent_trait_pred.def_id(); - if tcx.is_diagnostic_item(sym::FromResidual, parent_def_id) + if tcx.is_diagnostic_item(sym::TryFromBreak, parent_def_id) && !tcx.features().enabled(sym::try_trait_v2) { // If `#![feature(try_trait_v2)]` is not enabled, then there's no point on - // talking about `FromResidual>`, as the end user has nothing they + // talking about `TryFromBreak>`, as the end user has nothing they // can do about it. As far as they are concerned, `?` is compiler magic. return; } @@ -6464,7 +6465,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err: &mut Diag<'_>, trait_pred: ty::PolyTraitClause<'tcx>, ) { - if ObligationCauseCode::QuestionMark != *obligation.cause.code().peel_derives() { + if ObligationCauseCode::QuestionMarkIntoTry != *obligation.cause.code().peel_derives() { return; } @@ -6503,10 +6504,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let node = self.tcx.hir_node_by_def_id(obligation.cause.body_def_id); if let Some((fn_decl, body_id)) = choose_suggest_items(self.tcx, node) && let hir::FnRetTy::DefaultReturn(ret_span) = fn_decl.output - && self.tcx.is_diagnostic_item(sym::FromResidual, trait_pred.def_id()) + // () as TryFromBreak<_, TryResult> + && self.tcx.is_diagnostic_item(sym::TryFromBreak, trait_pred.def_id()) && trait_pred.skip_binder().trait_ref.args.type_at(0).is_unit() - && let ty::Adt(def, _) = trait_pred.skip_binder().trait_ref.args.type_at(1).kind() - && self.tcx.is_diagnostic_item(sym::Result, def.did()) + && let ty::Adt(def, _) = trait_pred.skip_binder().trait_ref.args.type_at(2).kind() + && self.tcx.is_diagnostic_item(sym::TryResult, def.did()) { let mut sugg_spans = vec![(ret_span, " -> Result<(), Box>".to_string())]; diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 6477858f14b83..81f17528b8724 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -199,7 +199,7 @@ use core::ops::{ DerefPure, DispatchFromDyn, LegacyReceiver, }; #[cfg(not(no_global_oom_handling))] -use core::ops::{Residual, Try}; +use core::ops::{Try, TryAs}; use core::pin::{Pin, PinSafePointer}; use core::ptr::{self, NonNull, Unique}; use core::task::{Context, Poll}; @@ -746,10 +746,9 @@ impl Box { pub fn try_map( this: Self, f: impl FnOnce(T) -> R, - ) -> >>::TryType + ) -> ::Output, A>>>::Try where - R: Try, - R::Residual: Residual>, + R: TryAs::Output, A>>, { let (value, allocation) = Box::take(this); let (raw, alloc) = Box::into_non_null_with_allocator(allocation); diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 4fb34ed5b2668..85c503b553bbb 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -181,7 +181,6 @@ #![feature(trusted_random_access)] #![feature(try_blocks)] #![feature(try_trait_v2)] -#![feature(try_trait_v2_residual)] #![feature(tuple_trait)] #![feature(ub_checks)] #![feature(unicode_internals)] diff --git a/library/alloc/src/rcs/arc.rs b/library/alloc/src/rcs/arc.rs index ffa848998e9a2..6ae7039568978 100644 --- a/library/alloc/src/rcs/arc.rs +++ b/library/alloc/src/rcs/arc.rs @@ -12,7 +12,7 @@ use core::mem::{self, Alignment, ManuallyDrop}; use core::num::NonZeroUsize; use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver}; #[cfg(not(no_global_oom_handling))] -use core::ops::{Residual, Try}; +use core::ops::{Try, TryAs}; use core::panic::{RefUnwindSafe, UnwindSafe}; use core::pin::{Pin, PinSafePointer}; use core::ptr::{self, NonNull}; @@ -1261,10 +1261,9 @@ impl Arc { pub fn try_map( this: Self, f: impl FnOnce(&T) -> R, - ) -> >>::TryType + ) -> ::Output, A>>>::Try where - R: Try, - R::Residual: Residual>, + R: TryAs::Output, A>>, { if size_of::() == size_of::() && align_of::() == align_of::() @@ -4933,10 +4932,9 @@ impl UniqueArc { pub fn try_map( this: Self, f: impl FnOnce(T) -> R, - ) -> >>::TryType + ) -> >>::Try where - R: Try, - R::Residual: Residual>, + R: TryAs::Output, A>>, { if size_of::() == size_of::() && align_of::() == align_of::() diff --git a/library/alloc/src/rcs/rc.rs b/library/alloc/src/rcs/rc.rs index dd5c9e0013b95..e1f78efd94253 100644 --- a/library/alloc/src/rcs/rc.rs +++ b/library/alloc/src/rcs/rc.rs @@ -255,7 +255,7 @@ use core::mem::{self, Alignment, ManuallyDrop}; use core::num::NonZeroUsize; use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver}; #[cfg(not(no_global_oom_handling))] -use core::ops::{Residual, Try}; +use core::ops::{Try, TryAs}; use core::panic::{RefUnwindSafe, UnwindSafe}; #[cfg(not(no_global_oom_handling))] use core::pin::Pin; @@ -1104,13 +1104,9 @@ impl Rc { /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "smart_pointer_try_map", issue = "144419")] - pub fn try_map( - this: Self, - f: impl FnOnce(&T) -> R, - ) -> >>::TryType + pub fn try_map(this: Self, f: impl FnOnce(&T) -> R) -> >>::Try where - R: Try, - R::Residual: Residual>, + R: Try + TryAs>, { if size_of::() == size_of::() && align_of::() == align_of::() @@ -4512,10 +4508,9 @@ impl UniqueRc { pub fn try_map( this: Self, f: impl FnOnce(T) -> R, - ) -> >>::TryType + ) -> ::Output, A>>>::Try where - R: Try, - R::Residual: Residual>, + R: TryAs::Output, A>>, { if size_of::() == size_of::() && align_of::() == align_of::() diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index fcd635a03c652..0d7ccbd3143ae 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -13,9 +13,7 @@ use crate::intrinsics::transmute_unchecked; use crate::iter::{TrustedLen, repeat_n}; use crate::marker::Destruct; use crate::mem::{self, ManuallyDrop, MaybeUninit}; -use crate::ops::{ - ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try, -}; +use crate::ops::{ControlFlow, Index, IndexMut, NeverShortCircuit, Try, TryAs, TryFromBreak}; use crate::ptr::{null, null_mut}; use crate::slice::{Iter, IterMut}; use crate::{fmt, ptr}; @@ -145,14 +143,14 @@ where #[inline] #[unstable(feature = "array_try_from_fn", issue = "89379")] #[rustc_const_unstable(feature = "array_try_from_fn", issue = "89379")] -pub const fn try_from_fn(cb: F) -> ChangeOutputType +pub const fn try_from_fn(cb: F) -> ::Output; N]>>::Try where - R: [const] Try, Output: [const] Destruct>, + R: [const] Try + [const] TryAs<[::Output; N]>, F: [const] FnMut(usize) -> R + [const] Destruct, { let mut array = [const { MaybeUninit::uninit() }; N]; match try_from_fn_erased(&mut array, cb) { - ControlFlow::Break(r) => FromResidual::from_residual(r), + ControlFlow::Break(r) => TryFromBreak::from_break(r), ControlFlow::Continue(()) => { // SAFETY: All elements of the array were populated. try { unsafe { MaybeUninit::array_assume_init(array) } } @@ -650,10 +648,10 @@ impl [T; N] { pub const fn try_map( self, mut f: impl [const] FnMut(T) -> R + [const] Destruct, - ) -> ChangeOutputType + ) -> ::Output; N]>>::Try where - R: [const] Try, Output: [const] Destruct>, T: [const] Destruct, + R: [const] Try + [const] TryAs<[::Output; N]>, { let mut me = ManuallyDrop::new(self); // SAFETY: try_from_fn calls `f` N times. @@ -923,7 +921,7 @@ impl [T; N] { const fn try_from_fn_erased>( buffer: &mut [MaybeUninit], mut generator: impl [const] FnMut(usize) -> R + [const] Destruct, -) -> ControlFlow { +) -> ControlFlow { let mut guard = Guard { array_mut: buffer, initialized: 0 }; while guard.initialized < guard.array_mut.len() { diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index ca950a138f31c..9af8f11fb966c 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1,6 +1,6 @@ use crate::iter::InPlaceIterable; use crate::num::NonZero; -use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; +use crate::ops::{ControlFlow, Try, TryAs, TryFromBreak}; mod array_chunks; mod by_ref_sized; @@ -147,13 +147,12 @@ pub(crate) struct GenericShunt<'a, I, R> { } /// Process the given iterator as if it yielded the item's `Try::Output` -/// type instead. Any `Try::Residual`s encountered will stop the inner iterator +/// type instead. Any `Try::Break`s encountered will stop the inner iterator /// and be propagated back to the overall result. -pub(crate) fn try_process(iter: I, mut f: F) -> ChangeOutputType +pub(crate) fn try_process(iter: I, mut f: F) -> >::Try where - I: Iterator>, - for<'a> F: FnMut(GenericShunt<'a, I, R>) -> U, - R: Residual, + I: Iterator + TryAs>, + for<'a> F: FnMut(GenericShunt<'a, I, B>) -> U, { // FIXME(#11084): we might be able to get rid of GenericShunt in favor of // Iterator::scan, as performance should be comparable @@ -162,14 +161,14 @@ where let shunt = GenericShunt { iter, residual: &mut residual }; let value = f(shunt); match residual { - Some(r) => FromResidual::from_residual(r), + Some(r) => TryFromBreak::from_break(r), None => Try::from_output(value), } } -impl Iterator for GenericShunt<'_, I, R> +impl Iterator for GenericShunt<'_, I, B> where - I: Iterator>, + I: Iterator>, { type Item = ::Output; @@ -186,10 +185,10 @@ where } } - fn try_fold(&mut self, init: B, mut f: F) -> T + fn try_fold(&mut self, init: S, mut f: F) -> T where - F: FnMut(B, Self::Item) -> T, - T: Try, + F: FnMut(S, Self::Item) -> T, + T: Try, { self.iter .try_fold(init, |acc, x| match Try::branch(x) { diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs index 4bddc2025c26e..b2295697073a3 100644 --- a/library/core/src/iter/adapters/peekable.rs +++ b/library/core/src/iter/adapters/peekable.rs @@ -144,7 +144,7 @@ where ControlFlow::Continue(acc) => f(acc, v), ControlFlow::Break(r) => { self.peeked = Some(Some(v)); - R::from_residual(r) + R::from_break(r) } }, None => self.iter.try_rfold(init, f), diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index cc4077d0ee26f..8054d48d2b7c8 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -9,7 +9,7 @@ use crate::array; use crate::cmp::{self, KeyAndValue, Ordering}; use crate::marker::Destruct; use crate::num::NonZero; -use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; +use crate::ops::{ControlFlow, Try, TryAs, TryFromBreak}; fn _assert_is_dyn_compatible(_: &dyn Iterator) {} @@ -2172,10 +2172,10 @@ pub const trait Iterator { #[inline] #[unstable(feature = "iterator_try_collect", issue = "94047")] #[rustc_non_const_trait_method] - fn try_collect(&mut self) -> ChangeOutputType + fn try_collect(&mut self) -> >::Try where Self: Sized, - Self::Item: Try>, + Self::Item: TryAs, B: FromIterator<::Output>, { try_process(ByRefSized(self), |i| i.collect()) @@ -2782,10 +2782,10 @@ pub const trait Iterator { fn try_reduce( &mut self, f: impl [const] FnMut(Self::Item, Self::Item) -> R + [const] Destruct, - ) -> ChangeOutputType> + ) -> >>::Try where Self: Sized, - R: [const] Try>>, + R: [const] Try + [const] TryAs>, { let first = match self.next() { Some(i) => i, @@ -2793,7 +2793,7 @@ pub const trait Iterator { }; match self.try_fold(first, f).branch() { - ControlFlow::Break(r) => FromResidual::from_residual(r), + ControlFlow::Break(r) => TryFromBreak::from_break(r), ControlFlow::Continue(i) => Try::from_output(Some(i)), } } @@ -3062,23 +3062,22 @@ pub const trait Iterator { fn try_find( &mut self, f: impl FnMut(&Self::Item) -> R, - ) -> ChangeOutputType> + ) -> >>::Try where Self: Sized, - R: Try>>, + R: Try + TryAs>, { #[inline] - fn check( + fn check( mut f: impl FnMut(&I) -> V, - ) -> impl FnMut((), I) -> ControlFlow + ) -> impl FnMut((), I) -> ControlFlow<>>::Try> where - V: Try, - R: Residual>, + V: Try + TryAs>, { move |(), x| match f(&x).branch() { ControlFlow::Continue(false) => ControlFlow::Continue(()), ControlFlow::Continue(true) => ControlFlow::Break(Try::from_output(Some(x))), - ControlFlow::Break(r) => ControlFlow::Break(FromResidual::from_residual(r)), + ControlFlow::Break(r) => ControlFlow::Break(TryFromBreak::from_break(r)), } } diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 56c9d0cf0cba7..0883ee41e5d19 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -100,11 +100,17 @@ pub enum ControlFlow { // is a no-op conversion in the `Try` implementation. } +/// The Try Kind specifically for `ControlFlow`. +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] +#[expect(missing_debug_implementations)] +pub struct TryControlFlow(()); + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] const impl ops::Try for ControlFlow { + type Kind = TryControlFlow; type Output = C; - type Residual = ControlFlow; + type Break = B; #[inline] fn from_output(output: Self::Output) -> Self { @@ -112,31 +118,26 @@ const impl ops::Try for ControlFlow { } #[inline] - fn branch(self) -> ControlFlow { - match self { - ControlFlow::Continue(c) => ControlFlow::Continue(c), - ControlFlow::Break(b) => ControlFlow::Break(ControlFlow::Break(b)), - } + fn branch(self) -> Self { + self } } #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] -// Note: manually specifying the residual type instead of using the default to work around +// Note: manually specifying the break type instead of using the default to work around // https://github.com/rust-lang/rust/issues/99940 -const impl ops::FromResidual> for ControlFlow { +const impl ops::TryFromBreak for ControlFlow { #[inline] - fn from_residual(residual: ControlFlow) -> Self { - match residual { - ControlFlow::Break(b) => ControlFlow::Break(b), - } + fn from_break(b: B) -> Self { + ControlFlow::Break(b) } } -#[unstable(feature = "try_trait_v2_residual", issue = "91285")] -#[rustc_const_unstable(feature = "const_try_residual", issue = "91285")] -const impl ops::Residual for ControlFlow { - type TryType = ControlFlow; +#[unstable(feature = "try_trait_v3", issue = "none")] +#[rustc_const_unstable(feature = "const_try", issue = "74935")] +impl ops::TryAs for ControlFlow { + type Try = ControlFlow; } impl ControlFlow { @@ -434,7 +435,7 @@ impl ControlFlow { { match R::branch(r) { ControlFlow::Continue(v) => ControlFlow::Continue(v), - ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)), + ControlFlow::Break(v) => ControlFlow::Break(R::from_break(v)), } } diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 9b5915a901aaa..f6349388fb7cf 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -191,13 +191,11 @@ pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive}; pub use self::range::{OneSidedRange, OneSidedRangeBound}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; -#[unstable(feature = "try_trait_v2_residual", issue = "91285")] -pub use self::try_trait::Residual; +pub(crate) use self::try_trait::NeverShortCircuit; #[unstable(feature = "try_trait_v2_yeet", issue = "96374")] pub use self::try_trait::Yeet; -pub(crate) use self::try_trait::{ChangeOutputType, NeverShortCircuit}; #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] -pub use self::try_trait::{FromResidual, Try}; +pub use self::try_trait::{Try, TryAs, TryFromBreak}; #[unstable(feature = "coerce_unsized", issue = "18598")] pub use self::unsize::CoerceUnsized; #[unstable(feature = "dispatch_from_dyn", issue = "none")] diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index d0dd6c8d5c8b7..779089e698796 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -73,7 +73,7 @@ use crate::ops::ControlFlow; /// } /// ``` /// -/// We'll also need [`FromResidual::from_residual`] to turn the residual back +/// We'll also need [`TryFromBreak::from_break`] to turn the residual back /// into the original type. But because it's a supertrait of `Try`, we don't /// need to mention it in the bounds. All types which implement `Try` can be /// recreated from their corresponding residual, so we'll just call it: @@ -89,7 +89,7 @@ use crate::ops::ControlFlow; /// let cf = f(accum, x).branch(); /// match cf { /// ControlFlow::Continue(a) => accum = a, -/// ControlFlow::Break(r) => return R::from_residual(r), +/// ControlFlow::Break(r) => return R::from_break(r), /// } /// } /// R::from_output(accum) @@ -130,12 +130,19 @@ use crate::ops::ControlFlow; #[doc(alias = "?")] #[lang = "Try"] #[rustc_const_unstable(feature = "const_try", issue = "74935")] -pub const trait Try: [const] FromResidual { +pub const trait Try: [const] TryFromBreak { + /// A marker type to signify the general meaning of the `?` operation on this type. + /// For example, `::Kind = TryResult`, and `TryResult` should be used for + /// custom "result-like" types which may contain an error. + /// When using `?` within a function, the return type of the function must implement + /// `TryFromBreak::Kind>` where `T` is the type of the target of `?`. + type Kind; + /// The type of the value produced by `?` when *not* short-circuiting. #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] type Output; - /// The type of the value passed to [`FromResidual::from_residual`] + /// The type of the value passed to [`TryFromBreak::from_break`] /// as part of `?` when short-circuiting. /// /// This represents the possible values of the `Self` type which are *not* @@ -148,8 +155,8 @@ pub const trait Try: [const] FromResidual { /// this type is typically a newtype of some sort to "color" the type /// so that it's distinguishable from the residuals of other types. /// - /// This is why `Result::Residual` is not `E`, but `Result`. - /// That way it's distinct from `ControlFlow::Residual`, for example, + /// This is why `Result::Break` is not `E`, but `Result`. + /// That way it's distinct from `ControlFlow::Break`, for example, /// and thus `?` on `ControlFlow` cannot be used in a method returning `Result`. /// /// If you're making a generic type `Foo` that implements `Try`, @@ -157,7 +164,7 @@ pub const trait Try: [const] FromResidual { /// type: that type will have a "hole" in the correct place, and will maintain the /// "foo-ness" of the residual so other types need to opt-in to interconversion. #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] - type Residual: Residual; + type Break; /// Constructs the type from its `Output` type. /// @@ -214,22 +221,21 @@ pub const trait Try: [const] FromResidual { /// ControlFlow::Break(ControlFlow::Break(3)), /// ); /// ``` - #[lang = "branch"] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] - fn branch(self) -> ControlFlow; + fn branch(self) -> ControlFlow; } /// Used to specify which residuals can be converted into which [`crate::ops::Try`] types. /// /// Every `Try` type needs to be recreatable from its own associated -/// `Residual` type, but can also have additional `FromResidual` implementations +/// `Residual` type, but can also have additional `TryFromBreak` implementations /// to support interconversion with other `Try` types. #[rustc_on_unimplemented( on( all( from_desugaring = "QuestionMark", Self = "core::result::Result", - R = "core::option::Option", + Kind = "core::option::TryOption", ), message = "the `?` operator can only be used on `Result`s, not `Option`s, \ in {ItemContext} that returns `Result`", @@ -246,18 +252,18 @@ pub const trait Try: [const] FromResidual { // and thus it can be phrased more strongly than `ControlFlow`'s. message = "the `?` operator can only be used on `Result`s \ in {ItemContext} that returns `Result`", - label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + label = "this `?` produces `{B}`, which is incompatible with `{Self}`", parent_label = "this function returns a `Result`" ), on( all( from_desugaring = "QuestionMark", Self = "core::option::Option", - R = "core::result::Result", + Kind = "core::result::TryResult", ), message = "the `?` operator can only be used on `Option`s, not `Result`s, \ in {ItemContext} that returns `Option`", - label = "use `.ok()?` if you want to discard the `{R}` error information", + label = "use `.ok()?` if you want to discard the `{B}` error information", parent_label = "this function returns an `Option`" ), on( @@ -269,18 +275,18 @@ pub const trait Try: [const] FromResidual { // residual, so this can also be phrased strongly. message = "the `?` operator can only be used on `Option`s \ in {ItemContext} that returns `Option`", - label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + label = "this `?` produces `{B}`, which is incompatible with `{Self}`", parent_label = "this function returns an `Option`" ), on( all( from_desugaring = "QuestionMark", Self = "core::ops::control_flow::ControlFlow", - R = "core::ops::control_flow::ControlFlow", + Kind = "core::ops::control_flow::TryControlFlow", ), message = "the `?` operator in {ItemContext} that returns `ControlFlow` \ can only be used on other `ControlFlow`s (with the same Break type)", - label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + label = "this `?` produces `{B}`, which is incompatible with `{Self}`", parent_label = "this function returns a `ControlFlow`", note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`" ), @@ -292,7 +298,7 @@ pub const trait Try: [const] FromResidual { ), message = "the `?` operator can only be used on `ControlFlow`s \ in {ItemContext} that returns `ControlFlow`", - label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + label = "this `?` produces `{B}`, which is incompatible with `{Self}`", parent_label = "this function returns a `ControlFlow`", ), on( @@ -304,33 +310,41 @@ pub const trait Try: [const] FromResidual { parent_label = "this function should return `Result` or `Option` to accept `?`" ), )] -#[rustc_diagnostic_item = "FromResidual"] +#[rustc_diagnostic_item = "TryFromBreak"] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] -pub const trait FromResidual::Residual> { +pub const trait TryFromBreak::Break, Kind = ::Kind> { /// Constructs the type from a compatible `Residual` type. /// /// This should be implemented consistently with the `branch` method such - /// that applying the `?` operator will get back an equivalent residual: - /// `FromResidual::from_residual(r).branch() --> ControlFlow::Break(r)`. - /// (The residual is not mandated to be *identical* when interconversion is involved.) + /// that applying the `?` operator will get back an equivalent break value: + /// `TryFromBreak::from_break(r).branch() --> ControlFlow::Break(r)`. + /// (The break value is not mandated to be *identical* when interconversion is involved.) /// /// # Examples /// /// ``` /// #![feature(try_trait_v2)] - /// use std::ops::{ControlFlow, FromResidual}; + /// use std::ops::{ControlFlow, TryFromBreak}; /// - /// assert_eq!(Result::::from_residual(Err(3_u8)), Err(3)); - /// assert_eq!(Option::::from_residual(None), None); + /// assert_eq!(Result::::from_break(Err(3_u8)), Err(3)); + /// assert_eq!(Option::::from_break(None), None); /// assert_eq!( - /// ControlFlow::<_, String>::from_residual(ControlFlow::Break(5)), + /// ControlFlow::<_, String>::from_break(ControlFlow::Break(5)), /// ControlFlow::Break(5), /// ); /// ``` - #[lang = "from_residual"] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] - fn from_residual(residual: R) -> Self; + fn from_break(b: B) -> Self; +} + +/// The `TryAs` trait is used to derive a type that is equivalent but with +/// `Try::Output` changed to `T`. +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] +#[rustc_const_unstable(feature = "const_try", issue = "74935")] +pub const trait TryAs: Try { + /// The Try type that is similar to Self, but with `Output` changed to `T` + type Try: [const] Try; } #[unstable( @@ -339,55 +353,64 @@ pub const trait FromResidual::Residual> { reason = "just here to simplify the desugaring; will never be stabilized" )] #[inline] -#[track_caller] // because `Result::from_residual` has it +#[track_caller] // because `Result::from_break` has it #[lang = "from_yeet"] #[allow(unreachable_pub)] // not-exposed but still used via lang-item pub fn from_yeet(yeeted: Y) -> T where - T: FromResidual>, + T: Try>, { - FromResidual::from_residual(Yeet(yeeted)) + T::from_break(yeeted.into()) } -/// Allows retrieving the canonical type implementing [`Try`] that has this type -/// as its residual and allows it to hold an `O` as its output. -/// -/// If you think of the `Try` trait as splitting a type into its [`Try::Output`] -/// and [`Try::Residual`] components, this allows putting them back together. -/// -/// For example, -/// `Result: Try>`, -/// and in the other direction, -/// ` as Residual>::TryType = Result`. -#[unstable(feature = "try_trait_v2_residual", issue = "91285")] -#[rustc_const_unstable(feature = "const_try_residual", issue = "91285")] -pub const trait Residual: Sized { - /// The "return" type of this meta-function. - #[unstable(feature = "try_trait_v2_residual", issue = "91285")] - // FIXME: ought to be implied - type TryType: [const] Try; -} - -/// Used in `try {}` blocks so the type produced in the `?` desugaring -/// depends on the residual type `R` and the output type of the block `O`, -/// but importantly not on the contextual type the way it would be if -/// we called `<_ as FromResidual>::from_residual(r)` directly. -#[unstable(feature = "try_trait_v2_residual", issue = "91285")] -#[rustc_const_unstable(feature = "const_try_residual", issue = "91285")] -// needs to be `pub` to avoid `private type` errors -#[expect(unreachable_pub)] +/// Used by `?` desugaring to call `Try::branch` and wrap the `Break` with `TryOperatorBreak`. +#[unstable(feature = "try_trait_v2", issue = "84277")] +#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[expect(unreachable_pub)] // only reachable via lang items #[inline] // FIXME: force would be nice, but fails -- see #148915 -#[lang = "into_try_type"] -pub const fn residual_into_try_type, O>( - r: R, -) -> >::TryType { - FromResidual::from_residual(r) +#[lang = "try_operator_branch"] +pub const fn try_operator_branch( + v: T, +) -> ControlFlow, T::Output> { + v.branch().map_break(TryOperatorBreak) } -#[unstable(feature = "pub_crate_should_not_need_unstable_attr", issue = "none")] -#[allow(type_alias_bounds)] -pub(crate) type ChangeOutputType>, V> = - >::TryType; +/// Used by `?` desugaring to wrap the `Break` value and reference the target +/// `Try` type in a type parameter, purely for type checking. +#[unstable(feature = "try_internals", issue = "none")] +#[rustc_diagnostic_item = "TryOperatorBreak"] +#[expect(unreachable_pub)] // only reachable via lang items +#[repr(transparent)] +pub struct TryOperatorBreak(T::Break) +// hack +where + T::Break: Sized; + +impl TryOperatorBreak { + #[unstable(feature = "try_internals", issue = "none")] + #[rustc_const_unstable(feature = "const_try", issue = "74935")] + #[expect(unreachable_pub)] // only reachable via lang items + #[lang = "into_try_heterogeneous"] + #[inline] + pub const fn into_try_heterogeneous(self) -> U + where + U: [const] TryFromBreak, + { + TryFromBreak::from_break(self.0) + } + + #[unstable(feature = "try_internals", issue = "none")] + #[rustc_const_unstable(feature = "const_try", issue = "74935")] + #[expect(unreachable_pub)] // only reachable via lang items + #[lang = "into_try_homogeneous"] + #[inline] + pub const fn into_try_homogeneous(self) -> >::Try + where + T: [const] TryAs, + { + TryFromBreak::from_break(self.0) + } +} /// An adapter for implementing non-try methods via the `Try` implementation. /// @@ -427,15 +450,21 @@ impl NeverShortCircuit { } } -pub(crate) enum NeverShortCircuitResidual {} +#[rustc_const_unstable(feature = "const_never_short_circuit", issue = "none")] +const impl TryAs for NeverShortCircuit { + type Try = NeverShortCircuit; +} + +pub(crate) struct TryNeverShortCircuit(()); #[rustc_const_unstable(feature = "const_never_short_circuit", issue = "none")] const impl Try for NeverShortCircuit { + type Kind = TryNeverShortCircuit; type Output = T; - type Residual = NeverShortCircuitResidual; + type Break = !; #[inline] - fn branch(self) -> ControlFlow { + fn branch(self) -> ControlFlow { ControlFlow::Continue(self.0) } @@ -444,19 +473,16 @@ const impl Try for NeverShortCircuit { NeverShortCircuit(x) } } + #[rustc_const_unstable(feature = "const_never_short_circuit", issue = "none")] -const impl FromResidual for NeverShortCircuit { +const impl TryFromBreak for NeverShortCircuit { #[inline] - fn from_residual(never: NeverShortCircuitResidual) -> Self { + fn from_break(never: !) -> Self { match never {} } } -#[rustc_const_unstable(feature = "const_never_short_circuit", issue = "none")] -const impl Residual for NeverShortCircuitResidual { - type TryType = NeverShortCircuit; -} -/// Implement `FromResidual>` on your type to enable +/// Implement `TryFromBreak>` on your type to enable /// `do yeet expr` syntax in functions returning your type. #[unstable(feature = "try_trait_v2_yeet", issue = "96374")] #[derive(Debug)] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index f53eb4a294194..b2cf3b74b2583 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -582,7 +582,7 @@ use crate::clone::TrivialClone; use crate::iter::{self, FusedIterator, TrustedLen}; use crate::marker::Destruct; use crate::num::NonZero; -use crate::ops::{self, ControlFlow, Deref, DerefMut, Residual, Try}; +use crate::ops::{self, ControlFlow, Deref, DerefMut, Try, TryAs}; use crate::panicking::{panic, panic_display}; use crate::pin::Pin; use crate::{cmp, hint, mem, slice}; @@ -1859,13 +1859,10 @@ impl Option { /// ``` #[inline] #[unstable(feature = "option_get_or_try_insert_with", issue = "143648")] - pub fn get_or_try_insert_with<'a, R, F>( - &'a mut self, - f: F, - ) -> >::TryType + pub fn get_or_try_insert_with<'a, R, F>(&'a mut self, f: F) -> >::Try where F: FnOnce() -> R, - R: Try>, + R: Try + TryAs<&'a mut T>, { if let None = self { *self = Some(f()?); @@ -2860,11 +2857,18 @@ impl> FromIterator> for Option { } } +/// The Try Kind for short-circuiting when a value is absent. +/// The canonical type with this kind is `Option`. +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] +#[expect(missing_debug_implementations)] +pub struct TryOption(()); + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] const impl ops::Try for Option { + type Kind = TryOption; type Output = T; - type Residual = Option; + type Break = (); #[inline] fn from_output(output: Self::Output) -> Self { @@ -2872,41 +2876,29 @@ const impl ops::Try for Option { } #[inline] - fn branch(self) -> ControlFlow { + fn branch(self) -> ControlFlow { match self { Some(v) => ControlFlow::Continue(v), - None => ControlFlow::Break(None), + None => ControlFlow::Break(()), } } } #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] -// Note: manually specifying the residual type instead of using the default to work around +// Note: manually specifying the break type instead of using the default to work around // https://github.com/rust-lang/rust/issues/99940 -const impl ops::FromResidual> for Option { - #[inline] - fn from_residual(residual: Option) -> Self { - match residual { - None => None, - } - } -} - -#[diagnostic::do_not_recommend] -#[unstable(feature = "try_trait_v2_yeet", issue = "96374")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] -const impl ops::FromResidual> for Option { +const impl ops::TryFromBreak<(), TryOption> for Option { #[inline] - fn from_residual(ops::Yeet(()): ops::Yeet<()>) -> Self { + fn from_break(_: ()) -> Self { None } } -#[unstable(feature = "try_trait_v2_residual", issue = "91285")] +#[unstable(feature = "try_trait_v3", issue = "none")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] -const impl ops::Residual for Option { - type TryType = Option; +const impl ops::TryAs for Option { + type Try = Option; } impl Option> { diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 9d898df3c6d3c..06ef83492e021 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -2156,11 +2156,19 @@ impl> FromIterator> for Result { } } +/// The Try Kind for testing whether an error is present. +/// The canonical type with this kind is `Result`. +#[expect(missing_debug_implementations)] +#[rustc_diagnostic_item = "TryResult"] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] +pub struct TryResult(()); + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] const impl ops::Try for Result { + type Kind = TryResult; type Output = T; - type Residual = Result; + type Break = E; #[inline] fn from_output(output: Self::Output) -> Self { @@ -2168,37 +2176,26 @@ const impl ops::Try for Result { } #[inline] - fn branch(self) -> ControlFlow { + fn branch(self) -> ControlFlow { match self { Ok(v) => ControlFlow::Continue(v), - Err(e) => ControlFlow::Break(Err(e)), + Err(e) => ControlFlow::Break(e), } } } #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] -const impl> ops::FromResidual> for Result { +const impl> ops::TryFromBreak for Result { #[inline] #[track_caller] - fn from_residual(residual: Result) -> Self { - match residual { - Err(e) => Err(From::from(e)), - } - } -} -#[diagnostic::do_not_recommend] -#[unstable(feature = "try_trait_v2_yeet", issue = "96374")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] -const impl> ops::FromResidual> for Result { - #[inline] - fn from_residual(ops::Yeet(e): ops::Yeet) -> Self { + fn from_break(e: E) -> Self { Err(From::from(e)) } } -#[unstable(feature = "try_trait_v2_residual", issue = "91285")] +#[unstable(feature = "try_trait_v3", issue = "none")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] -const impl ops::Residual for Result { - type TryType = Result; +const impl ops::TryAs for Result { + type Try = Result; } diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index bad3cbe83ed65..a3444bfc7f535 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -1,6 +1,7 @@ #![stable(feature = "futures_api", since = "1.36.0")] use crate::ops::{self, ControlFlow}; +use crate::result::TryResult; /// Indicates whether a value is available or if the current task has been /// scheduled to receive a wakeup instead. @@ -231,8 +232,9 @@ const impl From for Poll { #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl ops::Try for Poll> { + type Kind = TryResult; type Output = Poll; - type Residual = Result; + type Break = E; #[inline] fn from_output(c: Self::Output) -> Self { @@ -240,29 +242,28 @@ impl ops::Try for Poll> { } #[inline] - fn branch(self) -> ControlFlow { + fn branch(self) -> ControlFlow { match self { Poll::Ready(Ok(x)) => ControlFlow::Continue(Poll::Ready(x)), - Poll::Ready(Err(e)) => ControlFlow::Break(Err(e)), + Poll::Ready(Err(e)) => ControlFlow::Break(e), Poll::Pending => ControlFlow::Continue(Poll::Pending), } } } #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] -impl> ops::FromResidual> for Poll> { +impl> ops::TryFromBreak for Poll> { #[inline] - fn from_residual(x: Result) -> Self { - match x { - Err(e) => Poll::Ready(Err(From::from(e))), - } + fn from_break(e: E) -> Self { + Poll::Ready(Err(From::from(e))) } } #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl ops::Try for Poll>> { + type Kind = TryResult; type Output = Poll>; - type Residual = Result; + type Break = E; #[inline] fn from_output(c: Self::Output) -> Self { @@ -270,10 +271,10 @@ impl ops::Try for Poll>> { } #[inline] - fn branch(self) -> ControlFlow { + fn branch(self) -> ControlFlow { match self { Poll::Ready(Some(Ok(x))) => ControlFlow::Continue(Poll::Ready(Some(x))), - Poll::Ready(Some(Err(e))) => ControlFlow::Break(Err(e)), + Poll::Ready(Some(Err(e))) => ControlFlow::Break(e), Poll::Ready(None) => ControlFlow::Continue(Poll::Ready(None)), Poll::Pending => ControlFlow::Continue(Poll::Pending), } @@ -281,11 +282,9 @@ impl ops::Try for Poll>> { } #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] -impl> ops::FromResidual> for Poll>> { +impl> ops::TryFromBreak for Poll>> { #[inline] - fn from_residual(x: Result) -> Self { - match x { - Err(e) => Poll::Ready(Some(Err(From::from(e)))), - } + fn from_break(e: E) -> Self { + Poll::Ready(Some(Err(From::from(e)))) } } diff --git a/library/coretests/tests/ops.rs b/library/coretests/tests/ops.rs index 1cbc625959886..cfd7963679c8f 100644 --- a/library/coretests/tests/ops.rs +++ b/library/coretests/tests/ops.rs @@ -1,5 +1,5 @@ mod control_flow; -mod from_residual; +mod from_break; use core::ops::{ Bound, Deref, DerefMut, OneSidedRange, OneSidedRangeBound, Range, RangeBounds, RangeFrom, diff --git a/library/coretests/tests/ops/from_break.rs b/library/coretests/tests/ops/from_break.rs new file mode 100644 index 0000000000000..edacbcc88c36c --- /dev/null +++ b/library/coretests/tests/ops/from_break.rs @@ -0,0 +1,27 @@ +//! Regression test that Option and ControlFlow can have downstream TryFromBreak impls. +//! cc https://github.com/rust-lang/rust/issues/99940, +//! This does NOT test that issue in general; Option and ControlFlow's TryFromBreak +//! impls in core were changed to not be affected by that issue. + +use core::ops::{ControlFlow, TryFromBreak}; + +struct Local; +struct TryLocal; + +impl TryFromBreak for Option { + fn from_break(_: Local) -> Option { + unimplemented!() + } +} + +impl TryFromBreak for ControlFlow { + fn from_break(_: Local) -> ControlFlow { + unimplemented!() + } +} + +impl TryFromBreak for Result { + fn from_break(_: Local) -> Result { + unimplemented!() + } +} diff --git a/library/coretests/tests/ops/from_residual.rs b/library/coretests/tests/ops/from_residual.rs deleted file mode 100644 index d5c86ccbcd317..0000000000000 --- a/library/coretests/tests/ops/from_residual.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! Regression test that Option and ControlFlow can have downstream FromResidual impls. -//! cc https://github.com/rust-lang/rust/issues/99940, -//! This does NOT test that issue in general; Option and ControlFlow's FromResidual -//! impls in core were changed to not be affected by that issue. - -use core::ops::{ControlFlow, FromResidual}; - -struct Local; - -impl FromResidual for Option { - fn from_residual(_: Local) -> Option { - unimplemented!() - } -} - -impl FromResidual for ControlFlow { - fn from_residual(_: Local) -> ControlFlow { - unimplemented!() - } -} - -impl FromResidual for Result { - fn from_residual(_: Local) -> Result { - unimplemented!() - } -} diff --git a/library/coretests/tests/result.rs b/library/coretests/tests/result.rs index 39898d5dbb76e..0de262e6d7588 100644 --- a/library/coretests/tests/result.rs +++ b/library/coretests/tests/result.rs @@ -414,12 +414,12 @@ fn result_try_trait_v2_branch() { use core::ops::Try; assert_eq!(Ok::(4).branch(), Continue(4)); - assert_eq!(Err::(4).branch(), Break(Err(4))); + assert_eq!(Err::(4).branch(), Break(4)); let one = NonZero::new(1).unwrap(); assert_eq!(Ok::<(), NonZero>(()).branch(), Continue(())); - assert_eq!(Err::<(), NonZero>(one).branch(), Break(Err(one))); + assert_eq!(Err::<(), NonZero>(one).branch(), Break(one)); assert_eq!(Ok::, ()>(one).branch(), Continue(one)); - assert_eq!(Err::, ()>(()).branch(), Break(Err(()))); + assert_eq!(Err::, ()>(()).branch(), Break(())); } // helper functions for const contexts diff --git a/src/tools/clippy/clippy_lints/src/matches/try_err.rs b/src/tools/clippy/clippy_lints/src/matches/try_err.rs index a61b87672e041..c873661fd780d 100644 --- a/src/tools/clippy/clippy_lints/src/matches/try_err.rs +++ b/src/tools/clippy/clippy_lints/src/matches/try_err.rs @@ -25,7 +25,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine // }; if let ExprKind::Call(match_fun, [try_arg]) = scrutinee.kind && let ExprKind::Path(match_fun_path) = match_fun.kind - && cx.tcx.qpath_is_lang_item(match_fun_path, LangItem::TryTraitBranch) + && cx.tcx.qpath_is_lang_item(match_fun_path, LangItem::TryOperatorBranch) && let ExprKind::Call(err_fun, [err_arg]) = try_arg.kind && err_fun.res(cx).ctor_parent(cx).is_lang_item(cx, ResultErr) && let Some(return_ty) = find_return_type(cx, &expr.kind) diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index 0891ffda6e7c3..53766a857bad4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -36,7 +36,7 @@ fn check_parent_is_suffix_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> ParentI if matches!( hir_callee.kind, ExprKind::Path(qpath) - if cx.tcx.qpath_is_lang_item(qpath, LangItem::TryTraitBranch) + if cx.tcx.qpath_is_lang_item(qpath, LangItem::TryOperatorBranch) ) { ParentIsSuffixExpr::Yes } else { diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index a173510dea7b8..adf95eb8cd4a5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -336,7 +336,7 @@ fn parse_iter_usage<'tcx>( .. }, [_], - ) if cx.tcx.qpath_is_lang_item(qpath, LangItem::TryTraitBranch) => { + ) if cx.tcx.qpath_is_lang_item(qpath, LangItem::TryOperatorBranch) => { let parent_span = e.span.parent_callsite().unwrap(); if parent_span.ctxt() == ctxt { (Some(UnwrapKind::QuestionMark), parent_span) diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index 740530d277066..281ba0041b91f 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -106,7 +106,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { && let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar(_)) = &arg.kind && let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind && let ExprKind::Path(qpath) = called.kind - && cx.tcx.qpath_is_lang_item(qpath, LangItem::TryTraitBranch) + && cx.tcx.qpath_is_lang_item(qpath, LangItem::TryOperatorBranch) && expr.span.eq_ctxt(inner_expr.span) && let expr_ty = cx.typeck_results().expr_ty(expr) && let inner_ty = cx.typeck_results().expr_ty(inner_expr) diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index 35e9d0a6d78a7..94c64e5455e7b 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -256,7 +256,7 @@ fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { fn unpack_try<'a>(cx: &LateContext<'_>, mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { while let ExprKind::Call(func, [arg_0]) = expr.kind && let ExprKind::Path(qpath) = func.kind - && cx.tcx.qpath_is_lang_item(qpath, LangItem::TryTraitBranch) + && cx.tcx.qpath_is_lang_item(qpath, LangItem::TryOperatorBranch) { expr = arg_0; } diff --git a/src/tools/clippy/tests/ui/manual_try_fold.rs b/src/tools/clippy/tests/ui/manual_try_fold.rs index 0c12d74820d14..62d23a485dbef 100644 --- a/src/tools/clippy/tests/ui/manual_try_fold.rs +++ b/src/tools/clippy/tests/ui/manual_try_fold.rs @@ -2,7 +2,6 @@ #![warn(clippy::manual_try_fold)] #![expect(clippy::unnecessary_fold)] #![feature(try_trait_v2)] -#![feature(try_trait_v2_residual)] //@no-rustfix use std::ops::{ControlFlow, FromResidual, Residual, Try}; diff --git a/tests/codegen-units/item-collection/opaque-return-impls.rs b/tests/codegen-units/item-collection/opaque-return-impls.rs index d2781b356e976..a87b5cfccec4d 100644 --- a/tests/codegen-units/item-collection/opaque-return-impls.rs +++ b/tests/codegen-units/item-collection/opaque-return-impls.rs @@ -79,7 +79,7 @@ pub fn foo3() -> Box> { //~ MONO_ITEM fn ::nth //~ MONO_ITEM fn ::size_hint //~ MONO_ITEM fn ::try_fold::, {closure@::spec_advance_by::{closure#0}}, std::option::Option>> -//~ MONO_ITEM fn > as std::ops::FromResidual>>::from_residual +//~ MONO_ITEM fn > as std::ops::TryFromBreak>>::from_break //~ MONO_ITEM fn > as std::ops::Try>::branch //~ MONO_ITEM fn > as std::ops::Try>::from_output //~ MONO_ITEM fn foo3 diff --git a/tests/mir-opt/building/fallible_struct_drop.build.ElaborateDrops.diff b/tests/mir-opt/building/fallible_struct_drop.build.ElaborateDrops.diff index b6085e6c9b23b..c9175ceec1db8 100644 --- a/tests/mir-opt/building/fallible_struct_drop.build.ElaborateDrops.diff +++ b/tests/mir-opt/building/fallible_struct_drop.build.ElaborateDrops.diff @@ -157,7 +157,7 @@ _9 = copy ((_4 as Break).0: std::result::Result); StorageLive(_11); _11 = copy _9; - _0 = as FromResidual>>::from_residual(move _11) -> [return: bb6, unwind: bb90]; + _0 = as TryFromBreak>>::from_break(move _11) -> [return: bb6, unwind: bb90]; } bb6: { @@ -207,7 +207,7 @@ _19 = copy ((_14 as Break).0: std::result::Result); StorageLive(_21); _21 = copy _19; - _0 = as FromResidual>>::from_residual(move _21) -> [return: bb12, unwind: bb86]; + _0 = as TryFromBreak>>::from_break(move _21) -> [return: bb12, unwind: bb86]; } bb12: { @@ -256,7 +256,7 @@ _29 = copy ((_24 as Break).0: std::result::Result); StorageLive(_31); _31 = copy _29; - _0 = as FromResidual>>::from_residual(move _31) -> [return: bb18, unwind: bb81]; + _0 = as TryFromBreak>>::from_break(move _31) -> [return: bb18, unwind: bb81]; } bb18: { @@ -305,7 +305,7 @@ _39 = copy ((_34 as Break).0: std::result::Result); StorageLive(_41); _41 = copy _39; - _0 = as FromResidual>>::from_residual(move _41) -> [return: bb24, unwind: bb75]; + _0 = as TryFromBreak>>::from_break(move _41) -> [return: bb24, unwind: bb75]; } bb24: { @@ -353,7 +353,7 @@ _49 = copy ((_44 as Break).0: std::result::Result); StorageLive(_51); _51 = copy _49; - _0 = as FromResidual>>::from_residual(move _51) -> [return: bb30, unwind: bb68]; + _0 = as TryFromBreak>>::from_break(move _51) -> [return: bb30, unwind: bb68]; } bb30: { @@ -683,4 +683,3 @@ resume; } } - diff --git a/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-abort.mir b/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-abort.mir index e8efb9b7c3483..496ce125cad79 100644 --- a/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-abort.mir +++ b/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-abort.mir @@ -66,7 +66,7 @@ fn test() -> Option> { _8 = copy ((_5 as Break).0: std::option::Option); StorageLive(_10); _10 = copy _8; - _0 = > as FromResidual>>::from_residual(move _10) -> [return: bb6, unwind: bb13]; + _0 = > as TryFromBreak>>::from_break(move _10) -> [return: bb6, unwind: bb13]; } bb6: { diff --git a/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-unwind.mir b/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-unwind.mir index 4da1eed4484bb..c7f1f3789777e 100644 --- a/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-unwind.mir +++ b/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-unwind.mir @@ -66,7 +66,7 @@ fn test() -> Option> { _8 = copy ((_5 as Break).0: std::option::Option); StorageLive(_10); _10 = copy _8; - _0 = > as FromResidual>>::from_residual(move _10) -> [return: bb6, unwind: bb13]; + _0 = > as TryFromBreak>>::from_break(move _10) -> [return: bb6, unwind: bb13]; } bb6: { diff --git a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff index a822ca20a8e80..792a44f754003 100644 --- a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff @@ -15,7 +15,7 @@ scope 1 { debug residual => _6; scope 2 { - scope 8 (inlined #[track_caller] as FromResidual>>::from_residual) { + scope 8 (inlined #[track_caller] as TryFromBreak>>::from_break) { let mut _14: isize; let _15: i32; let mut _16: i32; @@ -140,4 +140,3 @@ + goto -> bb2; } } - diff --git a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff index a822ca20a8e80..792a44f754003 100644 --- a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff @@ -15,7 +15,7 @@ scope 1 { debug residual => _6; scope 2 { - scope 8 (inlined #[track_caller] as FromResidual>>::from_residual) { + scope 8 (inlined #[track_caller] as TryFromBreak>>::from_break) { let mut _14: isize; let _15: i32; let mut _16: i32; @@ -140,4 +140,3 @@ + goto -> bb2; } } - diff --git a/tests/mir-opt/pre-codegen/simple_option_map.map_via_question_mark.runtime-optimized.after.mir b/tests/mir-opt/pre-codegen/simple_option_map.map_via_question_mark.runtime-optimized.after.mir index 3c559614e9863..6dfeec8190416 100644 --- a/tests/mir-opt/pre-codegen/simple_option_map.map_via_question_mark.runtime-optimized.after.mir +++ b/tests/mir-opt/pre-codegen/simple_option_map.map_via_question_mark.runtime-optimized.after.mir @@ -10,7 +10,7 @@ fn map_via_question_mark(_1: Option) -> Option { scope 1 { debug residual => const Option::::None; scope 2 { - scope 7 (inlined as FromResidual>>::from_residual) { + scope 7 (inlined as TryFromBreak>>::from_break) { let mut _3: isize; let mut _5: bool; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-abort.mir index b42087b5c822d..bfdeb2d1d10cc 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-abort.mir @@ -32,7 +32,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } scope 20 { scope 21 { - scope 27 (inlined as FromResidual>>::from_residual) { + scope 27 (inlined as TryFromBreak>>::from_break) { let mut _21: isize; let mut _23: bool; } diff --git a/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff b/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff index be29296044837..76b7238e2a7b7 100644 --- a/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff +++ b/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff @@ -11,7 +11,7 @@ scope 1 { debug residual => _4; scope 2 { - scope 8 (inlined #[track_caller] as FromResidual>>::from_residual) { + scope 8 (inlined #[track_caller] as TryFromBreak>>::from_break) { let mut _10: isize; let _11: i32; let mut _12: bool; @@ -114,4 +114,3 @@ + goto -> bb2; } } - diff --git a/tests/rustdoc-html/inline_cross/auxiliary/issue-85454.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-85454.rs index be1ec49fdccb0..7f50739ad0a38 100644 --- a/tests/rustdoc-html/inline_cross/auxiliary/issue-85454.rs +++ b/tests/rustdoc-html/inline_cross/auxiliary/issue-85454.rs @@ -1,14 +1,14 @@ -//@ has issue_85454/trait.FromResidual.html -//@ has - '//pre[@class="rust item-decl"]' 'pub trait FromResidual::Residual> { fn from_residual(residual: R) -> Self; }' -pub trait FromResidual::Residual> { - fn from_residual(residual: R) -> Self; +//@ has issue_85454/trait.TryFromBreak.html +//@ has - '//pre[@class="rust item-decl"]' 'pub trait TryFromBreak::Break> { fn from_break(residual: R) -> Self; }' +pub trait TryFromBreak::Break> { + fn from_break(residual: R) -> Self; } -pub trait Try: FromResidual { +pub trait Try: TryFromBreak { type Output; - type Residual; + type Break; fn from_output(output: Self::Output) -> Self; - fn branch(self) -> ControlFlow; + fn branch(self) -> ControlFlow; } pub enum ControlFlow { diff --git a/tests/rustdoc-html/inline_cross/qpath-self-85454.rs b/tests/rustdoc-html/inline_cross/qpath-self-85454.rs index 4751b7b1db453..df5d15a80caa2 100644 --- a/tests/rustdoc-html/inline_cross/qpath-self-85454.rs +++ b/tests/rustdoc-html/inline_cross/qpath-self-85454.rs @@ -5,17 +5,17 @@ extern crate issue_85454; -//@ has foo/trait.FromResidual.html -//@ has - '//pre[@class="rust item-decl"]' 'pub trait FromResidual::Residual> { // Required method fn from_residual(residual: R) -> Self; }' -pub trait FromResidual::Residual> { - fn from_residual(residual: R) -> Self; +//@ has foo/trait.TryFromBreak.html +//@ has - '//pre[@class="rust item-decl"]' 'pub trait TryFromBreak::Break> { // Required method fn from_break(residual: R) -> Self; }' +pub trait TryFromBreak::Break> { + fn from_break(residual: R) -> Self; } -pub trait Try: FromResidual { +pub trait Try: TryFromBreak { type Output; - type Residual; + type Break; fn from_output(output: Self::Output) -> Self; - fn branch(self) -> ControlFlow; + fn branch(self) -> ControlFlow; } pub enum ControlFlow { @@ -24,7 +24,7 @@ pub enum ControlFlow { } pub mod reexport { - //@ has foo/reexport/trait.FromResidual.html - //@ has - '//pre[@class="rust item-decl"]' 'pub trait FromResidual::Residual> { // Required method fn from_residual(residual: R) -> Self; }' + //@ has foo/reexport/trait.TryFromBreak.html + //@ has - '//pre[@class="rust item-decl"]' 'pub trait TryFromBreak::Break> { // Required method fn from_break(residual: R) -> Self; }' pub use issue_85454::*; } diff --git a/tests/ui/async-await/async-closures/wrong-suggestion-result.stderr b/tests/ui/async-await/async-closures/wrong-suggestion-result.stderr index dc916165c0fd2..6f8b76d647d82 100644 --- a/tests/ui/async-await/async-closures/wrong-suggestion-result.stderr +++ b/tests/ui/async-await/async-closures/wrong-suggestion-result.stderr @@ -1,4 +1,4 @@ -error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/wrong-suggestion-result.rs:4:21 | LL | async fn once O>(f: F) -> O { @@ -9,9 +9,9 @@ LL | | Ok::<(), ()>(())?; LL | | } | |_- this function should return `Result` or `Option` to accept `?` | -help: consider restricting type parameter `O` with unstable trait `FromResidual` +help: consider restricting type parameter `O` with unstable trait `TryFromBreak` | -LL | async fn once>, F: AsyncFnOnce() -> O>(f: F) -> O { +LL | async fn once, F: AsyncFnOnce() -> O>(f: F) -> O { | ++++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0308]: mismatched types @@ -28,7 +28,7 @@ LL | f() = help: you may have forgotten to await an async function = note: it is currently not possible to add bounds constraining the future returned from an async function (`CallOnceFuture`) -error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/wrong-suggestion-result.rs:12:21 | LL | async fn fnref O>(f: F) -> O { @@ -39,9 +39,9 @@ LL | | Ok::<(), ()>(())?; LL | | } | |_- this function should return `Result` or `Option` to accept `?` | -help: consider restricting type parameter `O` with unstable trait `FromResidual` +help: consider restricting type parameter `O` with unstable trait `TryFromBreak` | -LL | async fn fnref>, F: AsyncFn() -> O>(f: F) -> O { +LL | async fn fnref, F: AsyncFn() -> O>(f: F) -> O { | ++++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0308]: mismatched types @@ -58,7 +58,7 @@ LL | f() = help: you may have forgotten to await an async function = note: it is currently not possible to add bounds constraining the future returned from an async function (`CallRefFuture`) -error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/wrong-suggestion-result.rs:21:21 | LL | async fn fnmut O>(f: F) -> O { @@ -69,9 +69,9 @@ LL | | Ok::<(), ()>(())?; LL | | } | |_- this function should return `Result` or `Option` to accept `?` | -help: consider restricting type parameter `O` with unstable trait `FromResidual` +help: consider restricting type parameter `O` with unstable trait `TryFromBreak` | -LL | async fn fnmut>, F: AsyncFnMut() -> O>(f: F) -> O { +LL | async fn fnmut, F: AsyncFnMut() -> O>(f: F) -> O { | ++++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0308]: mismatched types diff --git a/tests/ui/async-await/issue-84841.stderr b/tests/ui/async-await/issue-84841.stderr index 6c714ce7828ce..f516c1e861068 100644 --- a/tests/ui/async-await/issue-84841.stderr +++ b/tests/ui/async-await/issue-84841.stderr @@ -6,7 +6,7 @@ LL | test()?; | = help: the nightly-only, unstable trait `Try` is not implemented for `impl Future` -error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/issue-84841.rs:9:11 | LL | async fn foo() { diff --git a/tests/ui/async-await/try-on-option-in-async.stderr b/tests/ui/async-await/try-on-option-in-async.stderr index 332f4d4ec0c27..8eea550bbc327 100644 --- a/tests/ui/async-await/try-on-option-in-async.stderr +++ b/tests/ui/async-await/try-on-option-in-async.stderr @@ -1,4 +1,4 @@ -error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/try-on-option-in-async.rs:7:10 | LL | async { @@ -7,7 +7,7 @@ LL | let x: Option = None; LL | x?; | ^ cannot use the `?` operator in an async block that returns `{integer}` -error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/try-on-option-in-async.rs:16:10 | LL | let async_closure = async || { @@ -19,7 +19,7 @@ LL | | 22_u32 LL | | }; | |_____- this function should return `Result` or `Option` to accept `?` -error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/try-on-option-in-async.rs:25:6 | LL | async fn an_async_function() -> u32 { diff --git a/tests/ui/borrowck/moved-into-question-mark.rs b/tests/ui/borrowck/moved-into-question-mark.rs index d09b7b8f6f42d..41e01adcb2dd7 100644 --- a/tests/ui/borrowck/moved-into-question-mark.rs +++ b/tests/ui/borrowck/moved-into-question-mark.rs @@ -7,10 +7,12 @@ fn main() -> io::Result<()> { //~^ NOTE move occurs because `entry` has type `Result let file_type = entry?.file_type()?; //~^ NOTE `entry` moved due to the question mark operator + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` if file_type.is_dir() { dbg!(entry?.file_name()); //~ ERROR use of moved value //~^ NOTE value used here after move - //~| NOTE the question mark operator is desugared into a call to `std::ops::Try::branch` + //~| NOTE in this expansion of desugaring of operator `?` } } Ok(()) diff --git a/tests/ui/borrowck/moved-into-question-mark.stderr b/tests/ui/borrowck/moved-into-question-mark.stderr index 5febf1b73b473..8462a4dcb65a0 100644 --- a/tests/ui/borrowck/moved-into-question-mark.stderr +++ b/tests/ui/borrowck/moved-into-question-mark.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `entry` - --> $DIR/moved-into-question-mark.rs:11:18 + --> $DIR/moved-into-question-mark.rs:13:18 | LL | for entry in fs::read_dir(".")? { | ----- move occurs because `entry` has type `Result`, which does not implement the `Copy` trait @@ -8,14 +8,16 @@ LL | let file_type = entry?.file_type()?; | ------ `entry` moved due to the question mark operator ... LL | dbg!(entry?.file_name()); - | ^^^^^ value used here after move + | ^^^^^^ value used here after move | -note: the question mark operator is desugared into a call to `std::ops::Try::branch`, which takes ownership of the receiver `self`, which moves `entry` - --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL +help: borrow this binding in the pattern to avoid moving the value + | +LL | let file_type = ref entry?.file_type()?; + | +++ help: you could `clone` the value and consume it, if the following trait bounds could be satisfied: `DirEntry: Clone` and `std::io::Error: Clone` | -LL | let file_type = entry.clone()?.file_type()?; - | ++++++++ +LL | let file_type = entry?.clone().file_type()?; + | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-try-feature-gate.rs b/tests/ui/consts/const-try-feature-gate.rs index 4a98185a18a7f..ffcbe18019765 100644 --- a/tests/ui/consts/const-try-feature-gate.rs +++ b/tests/ui/consts/const-try-feature-gate.rs @@ -4,8 +4,8 @@ const fn t() -> Option<()> { Some(())?; //~^ ERROR `?` is not allowed //~| ERROR `?` is not allowed - //~| ERROR `Try` is not yet stable as a const trait - //~| ERROR `FromResidual` is not yet stable as a const trait + //~| ERROR `?` is not yet stable in const contexts + //~| ERROR `?` is not yet stable in const contexts None } diff --git a/tests/ui/consts/const-try-feature-gate.stderr b/tests/ui/consts/const-try-feature-gate.stderr index eb5728aaaa78e..a9e440e222e9d 100644 --- a/tests/ui/consts/const-try-feature-gate.stderr +++ b/tests/ui/consts/const-try-feature-gate.stderr @@ -9,7 +9,7 @@ LL | Some(())?; = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `Try` is not yet stable as a const trait +error: `?` is not yet stable in const contexts --> $DIR/const-try-feature-gate.rs:4:5 | LL | Some(())?; @@ -32,12 +32,13 @@ LL | Some(())?; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: `FromResidual` is not yet stable as a const trait +error: `?` is not yet stable in const contexts --> $DIR/const-try-feature-gate.rs:4:5 | LL | Some(())?; | ^^^^^^^^^ | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: add `#![feature(const_try)]` to the crate attributes to enable | LL + #![feature(const_try)] diff --git a/tests/ui/consts/const-try.rs b/tests/ui/consts/const-try.rs index fb958f911c4af..115ec58304c12 100644 --- a/tests/ui/consts/const-try.rs +++ b/tests/ui/consts/const-try.rs @@ -7,36 +7,33 @@ #![crate_type = "lib"] #![feature(try_trait_v2)] -#![feature(try_trait_v2_residual)] #![feature(const_trait_impl)] #![feature(const_try)] -use std::ops::{ControlFlow, FromResidual, Residual, Try}; +use std::ops::{ControlFlow, TryFromBreak, Try}; +use std::result::TryResult; struct TryMe; struct Error; -const impl FromResidual for TryMe { - fn from_residual(residual: Error) -> Self { +const impl TryFromBreak for TryMe { + fn from_break(residual: Error) -> Self { TryMe } } const impl Try for TryMe { + type Kind = TryResult; type Output = (); - type Residual = Error; + type Break = Error; fn from_output(output: Self::Output) -> Self { TryMe } - fn branch(self) -> ControlFlow { + fn branch(self) -> ControlFlow { ControlFlow::Break(Error) } } -impl Residual<()> for Error { - type TryType = TryMe; -} - const fn t() -> TryMe { TryMe?; TryMe diff --git a/tests/ui/inference/question-mark-type-infer.stderr b/tests/ui/inference/question-mark-type-infer.stderr index b531d42ff93cf..8de8e850bd8f6 100644 --- a/tests/ui/inference/question-mark-type-infer.stderr +++ b/tests/ui/inference/question-mark-type-infer.stderr @@ -9,8 +9,8 @@ note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL help: consider specifying the generic argument | -LL | l.iter().map(f).collect::>()? - | ++++++++++++++++ +LL | l.iter().map(f).collect::>()? + | ++++++++++ error[E0283]: type annotations needed --> $DIR/question-mark-type-infer.rs:16:29 @@ -23,8 +23,8 @@ note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL help: consider specifying the generic argument | -LL | let x = l.iter().map(f).collect::>()?; - | ++++++++++++++++ +LL | let x = l.iter().map(f).collect::>()?; + | ++++++++++ error[E0283]: type annotations needed --> $DIR/question-mark-type-infer.rs:23:39 @@ -37,8 +37,8 @@ note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL help: consider specifying the generic argument | -LL | let x: Vec = l.iter().map(f).collect::>()?; - | ++++++++++++++++ +LL | let x: Vec = l.iter().map(f).collect::>()?; + | ++++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/inference/question-mark-type-inference-in-chain.stderr b/tests/ui/inference/question-mark-type-inference-in-chain.stderr index 5c0a739f4e6b0..43eeb1415072d 100644 --- a/tests/ui/inference/question-mark-type-inference-in-chain.stderr +++ b/tests/ui/inference/question-mark-type-inference-in-chain.stderr @@ -26,8 +26,8 @@ note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL help: consider specifying the generic argument | -LL | let mut tags: Vec = lines.iter().map(|e| parse(e)).collect::>()?; - | ++++++++++++++++ +LL | let mut tags: Vec = lines.iter().map(|e| parse(e)).collect::>()?; + | ++++++++++ error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/question-mark-type-inference-in-chain.rs:60:20 diff --git a/tests/ui/return/return-from-residual-sugg-issue-125997.stderr b/tests/ui/return/return-from-residual-sugg-issue-125997.stderr index 86981860677bc..07c736318a073 100644 --- a/tests/ui/return/return-from-residual-sugg-issue-125997.stderr +++ b/tests/ui/return/return-from-residual-sugg-issue-125997.stderr @@ -1,4 +1,4 @@ -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/return-from-residual-sugg-issue-125997.rs:10:44 | LL | fn test1() { @@ -14,7 +14,7 @@ LL | LL + Ok(()) | -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/return-from-residual-sugg-issue-125997.rs:15:44 | LL | fn test2() { @@ -31,7 +31,7 @@ LL | println!(); LL + Ok(()) | -error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/return-from-residual-sugg-issue-125997.rs:34:48 | LL | fn test4(&self) { @@ -48,7 +48,7 @@ LL ~ Ok(()) LL ~ } | -error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/return-from-residual-sugg-issue-125997.rs:39:48 | LL | fn test5(&self) { @@ -66,7 +66,7 @@ LL ~ Ok(()) LL ~ } | -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/return-from-residual-sugg-issue-125997.rs:46:44 | LL | fn main() { @@ -83,7 +83,7 @@ LL | mac!(); LL + Ok(()) | -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/return-from-residual-sugg-issue-125997.rs:23:52 | LL | macro_rules! mac { diff --git a/tests/ui/traits/const-traits/auxiliary/minicore.rs b/tests/ui/traits/const-traits/auxiliary/minicore.rs index e1d1135e6d4ec..0ca7aa0517653 100644 --- a/tests/ui/traits/const-traits/auxiliary/minicore.rs +++ b/tests/ui/traits/const-traits/auxiliary/minicore.rs @@ -57,20 +57,20 @@ const fn bar() { } #[lang = "Try"] -pub const trait Try: FromResidual { +pub const trait Try: TryFromBreak { type Output; - type Residual; + type Break; #[lang = "from_output"] fn from_output(output: Self::Output) -> Self; #[lang = "branch"] - fn branch(self) -> ControlFlow; + fn branch(self) -> ControlFlow; } -pub const trait FromResidual::Residual> { - #[lang = "from_residual"] - fn from_residual(residual: R) -> Self; +pub const trait TryFromBreak::Break> { + #[lang = "from_break"] + fn from_break(residual: R) -> Self; } enum ControlFlow { @@ -133,7 +133,7 @@ pub const trait Drop { } pub const trait Residual { - type TryType: [const] Try + Try; + type TryType: [const] Try + Try; } const fn size_of() -> usize { diff --git a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs index ce4350673972f..1a11c213f64bc 100644 --- a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs +++ b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs @@ -1,11 +1,11 @@ #![allow(incomplete_features)] #![feature(const_trait_impl, const_try, try_trait_v2)] -use std::ops::FromResidual; +use std::ops::TryFromBreak; -const impl FromResidual for T { +const impl TryFromBreak for T { //~^ ERROR type parameter `T` must be used as an argument to some local type - fn from_residual(t: T) -> _ { + fn from_break(t: T) -> _ { //~^ ERROR the placeholder `_` is not allowed t } diff --git a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr index 6096786031364..273d9cf5d2896 100644 --- a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr +++ b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr @@ -1,7 +1,7 @@ error[E0210]: type parameter `T` must be used as an argument to some local type (e.g., `MyStruct`) --> $DIR/ice-119717-constant-lifetime.rs:6:12 | -LL | const impl FromResidual for T { +LL | const impl TryFromBreak for T { | ^ uncovered type parameter | = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local @@ -10,13 +10,13 @@ LL | const impl FromResidual for T { error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated functions --> $DIR/ice-119717-constant-lifetime.rs:8:31 | -LL | fn from_residual(t: T) -> _ { +LL | fn from_break(t: T) -> _ { | ^ not allowed in type signatures | help: try replacing `_` with the type in the corresponding trait method signature | -LL - fn from_residual(t: T) -> _ { -LL + fn from_residual(t: T) -> T { +LL - fn from_break(t: T) -> _ { +LL + fn from_break(t: T) -> T { | error: aborting due to 2 previous errors diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs index 11ebe4e318406..16a9f503bc12c 100644 --- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs +++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs @@ -1,21 +1,21 @@ #![allow(incomplete_features)] -#![feature(const_trait_impl, try_trait_v2, try_trait_v2_residual, const_try, const_try_residual)] -use std::ops::{FromResidual, Residual, Try}; +#![feature(const_trait_impl, try_trait_v2, const_try)] +use std::ops::{TryFromBreak, Try}; struct TryMe; struct Error; -const impl FromResidual for TryMe {} +const impl TryFromBreak for TryMe {} //~^ ERROR not all trait items implemented const impl Try for TryMe { //~^ ERROR not all trait items implemented type Output = (); - type Residual = Error; + type Break = Error; } -const impl Residual<()> for Error { - type TryType = TryMe; +const impl TryAs<()> for Error { + type Try = TryMe; } const fn t() -> TryMe { diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr index 77b715a8f577f..2aeb9e236bfff 100644 --- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr +++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr @@ -1,10 +1,10 @@ -error[E0046]: not all trait items implemented, missing: `from_residual` +error[E0046]: not all trait items implemented, missing: `from_break` --> $DIR/ice-126148-failed-to-normalize.rs:8:1 | -LL | const impl FromResidual for TryMe {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `from_residual` in implementation +LL | const impl TryFromBreak for TryMe {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `from_break` in implementation | - = help: implement the missing item: `fn from_residual(_: Error) -> Self { todo!() }` + = help: implement the missing item: `fn from_break(_: Error) -> Self { todo!() }` error[E0046]: not all trait items implemented, missing: `from_output`, `branch` --> $DIR/ice-126148-failed-to-normalize.rs:11:1 @@ -13,7 +13,7 @@ LL | const impl Try for TryMe { | ^^^^^^^^^^^^^^^^^^^^^^^^ missing `from_output`, `branch` in implementation | = help: implement the missing item: `fn from_output(_: ::Output) -> Self { todo!() }` - = help: implement the missing item: `fn branch(self) -> ControlFlow<::Residual, ::Output> { todo!() }` + = help: implement the missing item: `fn branch(self) -> ControlFlow<::Break, ::Output> { todo!() }` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/const-traits/trait-default-body-stability.rs b/tests/ui/traits/const-traits/trait-default-body-stability.rs index a8936b139cb46..2015435a9e573 100644 --- a/tests/ui/traits/const-traits/trait-default-body-stability.rs +++ b/tests/ui/traits/const-traits/trait-default-body-stability.rs @@ -5,12 +5,10 @@ #![feature(const_trait_impl)] #![feature(const_t_try)] #![feature(const_try)] -#![feature(const_try_residual)] #![feature(try_trait_v2)] -#![feature(try_trait_v2_residual)] #![stable(feature = "foo", since = "1.0")] -use std::ops::{ControlFlow, FromResidual, Residual, Try}; +use std::ops::{ControlFlow, TryFromBreak, Try, TryAs}; #[stable(feature = "foo", since = "1.0")] pub struct T; @@ -19,7 +17,7 @@ pub struct T; #[rustc_const_unstable(feature = "const_t_try", issue = "none")] const impl Try for T { type Output = T; - type Residual = T; + type Break = T; fn from_output(t: T) -> T { t @@ -32,14 +30,14 @@ const impl Try for T { #[stable(feature = "foo", since = "1.0")] #[rustc_const_unstable(feature = "const_t_try", issue = "none")] -const impl Residual for T { +const impl TryAs for T { type TryType = T; } #[stable(feature = "foo", since = "1.0")] #[rustc_const_unstable(feature = "const_t_try", issue = "none")] -const impl FromResidual for T { - fn from_residual(t: T) -> T { +const impl TryFromBreak for T { + fn from_break(t: T) -> T { t } } diff --git a/tests/ui/traits/next-solver/assembly/ambig-projection-self-is-ambig.rs b/tests/ui/traits/next-solver/assembly/ambig-projection-self-is-ambig.rs index e4332ced52142..019c7ed2e5153 100644 --- a/tests/ui/traits/next-solver/assembly/ambig-projection-self-is-ambig.rs +++ b/tests/ui/traits/next-solver/assembly/ambig-projection-self-is-ambig.rs @@ -8,7 +8,7 @@ trait Reader: Default { fn read_u8(&self) -> Result { let a: [u8; 1] = self.read_u8_array::<_>()?; - // This results in a nested ` as Try>::Residual: Sized` goal. + // This results in a nested ` as Try>::Break: Sized` goal. // The self type normalizes to `?0`. We previously did not force that to be // ambiguous but instead incompletely applied the `Self: Sized` candidate // from the `ParamEnv`, resulting in a type error. diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs index 9ac3b84dc122d..b82531a80cf18 100644 --- a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs +++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs @@ -1,14 +1,14 @@ -trait FromResidual::Residual> { - fn from_residual(residual: R) -> Self; +trait TryFromBreak::Break> { + fn from_break(residual: R) -> Self; } trait Try { - type Residual; + type Break; } fn w<'a, T: 'a, F: Fn(&'a T)>() { - let b: &dyn FromResidual = &(); - //~^ ERROR: the trait `FromResidual` is not dyn compatible + let b: &dyn TryFromBreak = &(); + //~^ ERROR: the trait `TryFromBreak` is not dyn compatible } fn main() {} diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr index 78a0743d9f87c..bd00214262338 100644 --- a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr +++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr @@ -1,24 +1,24 @@ -error[E0038]: the trait `FromResidual` is not dyn compatible +error[E0038]: the trait `TryFromBreak` is not dyn compatible --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:17 | -LL | let b: &dyn FromResidual = &(); - | ^^^^^^^^^^^^ `FromResidual` is not dyn compatible +LL | let b: &dyn TryFromBreak = &(); + | ^^^^^^^^^^^^ `TryFromBreak` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:2:8 | -LL | trait FromResidual::Residual> { +LL | trait TryFromBreak::Break> { | ------------ this trait is not dyn compatible... -LL | fn from_residual(residual: R) -> Self; - | ^^^^^^^^^^^^^ ...because associated function `from_residual` has no `self` parameter -help: consider turning `from_residual` into a method by giving it a `&self` argument, so that it is accessible through the trait object's vtable +LL | fn from_break(residual: R) -> Self; + | ^^^^^^^^^^^^^ ...because associated function `from_break` has no `self` parameter +help: consider turning `from_break` into a method by giving it a `&self` argument, so that it is accessible through the trait object's vtable | -LL | fn from_residual(&self, residual: R) -> Self; +LL | fn from_break(&self, residual: R) -> Self; | ++++++ -help: alternatively, consider constraining `from_residual` so it is explicitly marked as not applying to trait objects +help: alternatively, consider constraining `from_break` so it is explicitly marked as not applying to trait objects | -LL | fn from_residual(residual: R) -> Self where Self: Sized; +LL | fn from_break(residual: R) -> Self where Self: Sized; | +++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/question-mark-result-err-mismatch.rs b/tests/ui/traits/question-mark-result-err-mismatch.rs index bf6e219b86f71..362d1f5140b3b 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.rs +++ b/tests/ui/traits/question-mark-result-err-mismatch.rs @@ -18,7 +18,7 @@ fn foo() -> Result { //~ NOTE expected `String` because of this //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE the trait `From<()>` is not implemented for `String` //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - //~| NOTE required for `Result` to implement `FromResidual>` + //~| NOTE required for `Result` to implement `TryFromBreak<(), TryResult>` Ok(one.to_string()) } @@ -34,7 +34,7 @@ fn bar() -> Result<(), String> { //~ NOTE expected `String` because of this //~| NOTE this can't be annotated with `?` because it has type `Result<_, ()>` //~| NOTE the trait `From<()>` is not implemented for `String` //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - //~| NOTE required for `Result<(), String>` to implement `FromResidual>` + //~| NOTE required for `Result<(), String>` to implement `TryFromBreak<(), TryResult>` //~| HELP `String` implements trait `From`: Ok(one) } @@ -53,7 +53,7 @@ fn baz() -> Result { //~ NOTE expected `String` because of this //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE the trait `From<()>` is not implemented for `String` //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - //~| NOTE required for `Result` to implement `FromResidual>` + //~| NOTE required for `Result` to implement `TryFromBreak<(), TryResult>` Ok(one.to_string()) } diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr index 38639a9fb6229..66ec159c356d9 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.stderr +++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr @@ -14,7 +14,7 @@ LL | .map(|()| "")?; | ^ the trait `From<()>` is not implemented for `String` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required for `Result` to implement `FromResidual>` + = note: required for `Result` to implement `TryFromBreak<(), TryResult>` error[E0277]: `?` couldn't convert the error to `String` --> $DIR/question-mark-result-err-mismatch.rs:29:25 @@ -37,7 +37,7 @@ LL | .map_err(|_| ())?; From> From> From - = note: required for `Result<(), String>` to implement `FromResidual>` + = note: required for `Result<(), String>` to implement `TryFromBreak<(), TryResult>` error[E0277]: `?` couldn't convert the error to `String` --> $DIR/question-mark-result-err-mismatch.rs:49:11 @@ -55,7 +55,7 @@ LL | | })?; | this can't be annotated with `?` because it has type `Result<_, ()>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required for `Result` to implement `FromResidual>` + = note: required for `Result` to implement `TryFromBreak<(), TryResult>` error: aborting due to 3 previous errors diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index 51a9a8d759338..33911e95a5fb1 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -38,7 +38,7 @@ error[E0277]: the `?` operator can only be used on `Result`s in a function that LL | fn control_flow_to_result() -> Result { | -------------------------------------------------- this function returns a `Result` LL | Ok(ControlFlow::Break(123)?) - | ^ this `?` produces `ControlFlow<{integer}, !>`, which is incompatible with `Result` + | ^ this `?` produces `{integer}`, which is incompatible with `Result` error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` --> $DIR/bad-interconversion.rs:20:22 @@ -46,7 +46,11 @@ error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in LL | fn result_to_option() -> Option { | ------------------------------------ this function returns an `Option` LL | Some(Err("hello")?) - | ^ use `.ok()?` if you want to discard the `Result` error information + | ^ use `.ok()?` if you want to discard the `&str` error information + | +help: the trait `TryFromBreak<&str, TryResult>` is not implemented for `Option` + but trait `TryFromBreak<(), TryOption>` is implemented for it + --> $SRC_DIR/core/src/option.rs:LL:COL error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option` --> $DIR/bad-interconversion.rs:25:33 @@ -54,7 +58,11 @@ error[E0277]: the `?` operator can only be used on `Option`s in a function that LL | fn control_flow_to_option() -> Option { | ------------------------------------------ this function returns an `Option` LL | Some(ControlFlow::Break(123)?) - | ^ this `?` produces `ControlFlow<{integer}, !>`, which is incompatible with `Option` + | ^ this `?` produces `{integer}`, which is incompatible with `Option` + | +help: the trait `TryFromBreak<{integer}, ops::control_flow::TryControlFlow>` is not implemented for `Option` + but trait `TryFromBreak<(), TryOption>` is implemented for it + --> $SRC_DIR/core/src/option.rs:LL:COL error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` --> $DIR/bad-interconversion.rs:30:39 @@ -62,12 +70,11 @@ error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function LL | fn result_to_control_flow() -> ControlFlow { | -------------------------------------------------- this function returns a `ControlFlow` LL | ControlFlow::Continue(Err("hello")?) - | ^ this `?` produces `Result`, which is incompatible with `ControlFlow` + | ^ this `?` produces `&str`, which is incompatible with `ControlFlow` | -help: the trait `FromResidual>` is not implemented for `ControlFlow` - but trait `FromResidual>` is implemented for it +help: the trait `TryFromBreak<&str, TryResult>` is not implemented for `ControlFlow` + but trait `TryFromBreak` is implemented for it --> $SRC_DIR/core/src/ops/control_flow.rs:LL:COL - = help: for that trait implementation, expected `ControlFlow`, found `Result` error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` --> $DIR/bad-interconversion.rs:35:12 @@ -75,12 +82,11 @@ error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function LL | fn option_to_control_flow() -> ControlFlow { | ----------------------------------------------- this function returns a `ControlFlow` LL | Some(3)?; - | ^ this `?` produces `Option`, which is incompatible with `ControlFlow` + | ^ this `?` produces `()`, which is incompatible with `ControlFlow` | -help: the trait `FromResidual>` is not implemented for `ControlFlow` - but trait `FromResidual>` is implemented for it +help: the trait `TryFromBreak<(), TryOption>` is not implemented for `ControlFlow` + but trait `TryFromBreak` is implemented for it --> $SRC_DIR/core/src/ops/control_flow.rs:LL:COL - = help: for that trait implementation, expected `ControlFlow`, found `Option` error[E0277]: the `?` operator in a function that returns `ControlFlow` can only be used on other `ControlFlow`s (with the same Break type) --> $DIR/bad-interconversion.rs:41:29 @@ -88,11 +94,11 @@ error[E0277]: the `?` operator in a function that returns `ControlFlow` ca LL | fn control_flow_to_control_flow() -> ControlFlow { | ----------------------------------------------------- this function returns a `ControlFlow` LL | ControlFlow::Break(4_u8)?; - | ^ this `?` produces `ControlFlow`, which is incompatible with `ControlFlow` + | ^ this `?` produces `u8`, which is incompatible with `ControlFlow` | = note: unlike `Result`, there's no `From`-conversion performed for `ControlFlow` -help: the trait `FromResidual>` is not implemented for `ControlFlow` - but trait `FromResidual>` is implemented for it +help: the trait `TryFromBreak` is not implemented for `ControlFlow` + but trait `TryFromBreak` is implemented for it --> $SRC_DIR/core/src/ops/control_flow.rs:LL:COL = help: for that trait implementation, expected `i64`, found `u8` diff --git a/tests/ui/try-trait/bad-question-mark-on-trait-object.rs b/tests/ui/try-trait/bad-question-mark-on-trait-object.rs index 270ec2c532ac2..c11dd95bb7869 100644 --- a/tests/ui/try-trait/bad-question-mark-on-trait-object.rs +++ b/tests/ui/try-trait/bad-question-mark-on-trait-object.rs @@ -21,6 +21,8 @@ fn bat() -> Result<(), X> { //~ NOTE expected `X` because of this //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait //~| NOTE in this expansion //~| NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion } fn bar() -> Result<(), E> { Err(E) diff --git a/tests/ui/try-trait/bad-question-mark-on-trait-object.stderr b/tests/ui/try-trait/bad-question-mark-on-trait-object.stderr index 7639489b891a6..3a244b0e78552 100644 --- a/tests/ui/try-trait/bad-question-mark-on-trait-object.stderr +++ b/tests/ui/try-trait/bad-question-mark-on-trait-object.stderr @@ -32,6 +32,10 @@ note: `X` needs to implement `From` LL | struct X; | ^^^^^^^^ = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait +help: the trait `TryFromBreak` is not implemented for `Result<(), X>` + but trait `TryFromBreak` is implemented for it + --> $SRC_DIR/core/src/result.rs:LL:COL + = help: for that trait implementation, expected `X`, found `E` error: aborting due to 2 previous errors diff --git a/tests/ui/try-trait/option-to-result.stderr b/tests/ui/try-trait/option-to-result.stderr index 6ae9d840e0696..0668eebb65f39 100644 --- a/tests/ui/try-trait/option-to-result.stderr +++ b/tests/ui/try-trait/option-to-result.stderr @@ -6,6 +6,11 @@ LL | fn test_result() -> Result<(),()> { LL | let a:Option<()> = Some(()); LL | a?; | ^ use `.ok_or(...)?` to provide an error compatible with `Result<(), ()>` + | +help: the trait `TryFromBreak<(), TryOption>` is not implemented for `Result<(), ()>` + but trait `TryFromBreak<(), TryResult>` is implemented for it + --> $SRC_DIR/core/src/result.rs:LL:COL + = help: for that trait implementation, expected `TryResult`, found `TryOption` error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` --> $DIR/option-to-result.rs:11:6 @@ -14,7 +19,11 @@ LL | fn test_option() -> Option{ | ------------------------------- this function returns an `Option` LL | let a:Result = Ok(5); LL | a?; - | ^ use `.ok()?` if you want to discard the `Result` error information + | ^ use `.ok()?` if you want to discard the `i32` error information + | +help: the trait `TryFromBreak` is not implemented for `Option` + but trait `TryFromBreak<(), TryOption>` is implemented for it + --> $SRC_DIR/core/src/option.rs:LL:COL error: aborting due to 2 previous errors diff --git a/tests/ui/try-trait/try-as-monad.rs b/tests/ui/try-trait/try-as-monad.rs index 2854a160069e4..43aefdda1e11c 100644 --- a/tests/ui/try-trait/try-as-monad.rs +++ b/tests/ui/try-trait/try-as-monad.rs @@ -8,7 +8,7 @@ fn monad_unit(x: ::Output) -> T { T::from_output(x) } -fn monad_bind, T2: Try, R>( +fn monad_bind, T2: Try, B>( mx: T1, f: impl FnOnce(::Output) -> T2) -> T2 { diff --git a/tests/ui/try-trait/try-on-option-diagnostics.stderr b/tests/ui/try-trait/try-on-option-diagnostics.stderr index 08675e242a354..f016877d9146f 100644 --- a/tests/ui/try-trait/try-on-option-diagnostics.stderr +++ b/tests/ui/try-trait/try-on-option-diagnostics.stderr @@ -1,4 +1,4 @@ -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/try-on-option-diagnostics.rs:7:6 | LL | fn a_function() -> u32 { @@ -7,7 +7,7 @@ LL | let x: Option = None; LL | x?; | ^ cannot use the `?` operator in a function that returns `u32` -error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/try-on-option-diagnostics.rs:14:10 | LL | let a_closure = || { @@ -16,7 +16,7 @@ LL | let x: Option = None; LL | x?; | ^ cannot use the `?` operator in a closure that returns `{integer}` -error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/try-on-option-diagnostics.rs:26:14 | LL | fn a_method() { @@ -25,7 +25,7 @@ LL | let x: Option = None; LL | x?; | ^ cannot use the `?` operator in a method that returns `()` -error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/try-on-option-diagnostics.rs:39:14 | LL | fn a_trait_method() { diff --git a/tests/ui/try-trait/try-on-option.stderr b/tests/ui/try-trait/try-on-option.stderr index aeb519086d8c1..c31210cb92ff0 100644 --- a/tests/ui/try-trait/try-on-option.stderr +++ b/tests/ui/try-trait/try-on-option.stderr @@ -6,8 +6,13 @@ LL | fn foo() -> Result { LL | let x: Option = None; LL | x?; | ^ use `.ok_or(...)?` to provide an error compatible with `Result` + | +help: the trait `TryFromBreak<(), TryOption>` is not implemented for `Result` + but trait `TryFromBreak<(), TryResult>` is implemented for it + --> $SRC_DIR/core/src/result.rs:LL:COL + = help: for that trait implementation, expected `TryResult`, found `TryOption` -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/try-on-option.rs:11:6 | LL | fn bar() -> u32 { diff --git a/tests/ui/try-trait/try-operator-custom.rs b/tests/ui/try-trait/try-operator-custom.rs index 5b7170cc35e92..a8c1bcb5a07a7 100644 --- a/tests/ui/try-trait/try-operator-custom.rs +++ b/tests/ui/try-trait/try-operator-custom.rs @@ -1,69 +1,42 @@ //@ run-pass #![feature(try_trait_v2)] -#![feature(try_trait_v2_residual)] -use std::ops::{ControlFlow, FromResidual, Residual, Try}; +use std::ops::{ControlFlow, TryFromBreak, Try, TryAs}; +use std::result::TryResult; enum MyResult { Awesome(T), Terrible(U), } -enum Never {} - impl Try for MyResult { + type Kind = TryResult; type Output = U; - type Residual = MyResult; + type Break = V; fn from_output(u: U) -> MyResult { MyResult::Awesome(u) } - fn branch(self) -> ControlFlow { + fn branch(self) -> ControlFlow { match self { MyResult::Awesome(u) => ControlFlow::Continue(u), - MyResult::Terrible(e) => ControlFlow::Break(MyResult::Terrible(e)), - } - } -} - -impl FromResidual> for MyResult -where - V: Into, -{ - fn from_residual(x: MyResult) -> Self { - match x { - MyResult::Terrible(e) => MyResult::Terrible(e.into()), + MyResult::Terrible(e) => ControlFlow::Break(e), } } } -impl Residual for MyResult { - type TryType = MyResult; +impl TryAs for MyResult { + type Try = MyResult; } -type ResultResidual = Result; - -impl FromResidual> for MyResult +impl TryFromBreak for MyResult where - V: Into, + E: Into { - fn from_residual(x: ResultResidual) -> Self { - match x { - Err(e) => MyResult::Terrible(e.into()), - } - } -} - -impl FromResidual> for Result -where - V: Into, -{ - fn from_residual(x: MyResult) -> Self { - match x { - MyResult::Terrible(e) => Err(e.into()), - } + fn from_break(e: E) -> Self { + MyResult::Terrible(e.into()) } } diff --git a/tests/ui/try-trait/try-operator-on-main.rs b/tests/ui/try-trait/try-operator-on-main.rs index 3b364f7e7d39d..d9855c1f44441 100644 --- a/tests/ui/try-trait/try-operator-on-main.rs +++ b/tests/ui/try-trait/try-operator-on-main.rs @@ -8,7 +8,6 @@ fn main() { // a non-`Try` type on a non-`Try` fn ()?; //~ ERROR the `?` operator can only be applied to - //~^ ERROR the `?` operator can only be used in a function that // an unrelated use of `Try` try_trait_generic::<()>(); //~ ERROR the trait bound diff --git a/tests/ui/try-trait/try-operator-on-main.stderr b/tests/ui/try-trait/try-operator-on-main.stderr index d58720638aec1..04db1505af852 100644 --- a/tests/ui/try-trait/try-operator-on-main.stderr +++ b/tests/ui/try-trait/try-operator-on-main.stderr @@ -1,4 +1,4 @@ -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `TryFromBreak`) --> $DIR/try-operator-on-main.rs:7:31 | LL | fn main() { @@ -24,35 +24,26 @@ LL | ()?; | = help: the nightly-only, unstable trait `Try` is not implemented for `()` -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/try-operator-on-main.rs:10:7 - | -LL | fn main() { - | --------- this function should return `Result` or `Option` to accept `?` -... -LL | ()?; - | ^ cannot use the `?` operator in a function that returns `()` - error[E0277]: the trait bound `(): Try` is not satisfied - --> $DIR/try-operator-on-main.rs:14:25 + --> $DIR/try-operator-on-main.rs:13:25 | LL | try_trait_generic::<()>(); | ^^ the nightly-only, unstable trait `Try` is not implemented for `()` | note: required by a bound in `try_trait_generic` - --> $DIR/try-operator-on-main.rs:17:25 + --> $DIR/try-operator-on-main.rs:16:25 | LL | fn try_trait_generic() -> T { | ^^^ required by this bound in `try_trait_generic` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/try-operator-on-main.rs:19:5 + --> $DIR/try-operator-on-main.rs:18:5 | LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` | = help: the nightly-only, unstable trait `Try` is not implemented for `()` -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 025314709cf6c..5bd116ba1e236 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -244,7 +244,7 @@ mod expressions { type_ascribe!({ from_output(match branch(None) { Break { 0: residual } => #[allow(unreachable_code)] - break from_residual(residual), + break from_break(residual), Continue { 0: val } => #[allow(unreachable_code)] val, }) @@ -368,7 +368,7 @@ mod expressions { let expr; match branch(expr) { Break { 0: residual } => #[allow(unreachable_code)] - return from_residual(residual), + return from_break(residual), Continue { 0: val } => #[allow(unreachable_code)] val, };