| author | bors <bors@rust-lang.org> 2026-07-06 15:35:34 UTC |
| committer | bors <bors@rust-lang.org> 2026-07-06 15:35:34 UTC |
| log | 36714a9983d6ba11203d8bb87a1b372247fbcf06 |
| tree | 2b441c68cb73945c8f297305f33f23021788c28c |
| parent | 3c00c96d3af4d5b5e101e56cc161a608b21366ee |
| parent | 68dfc1d61f551e2aa49e18f911545d5e4c38544f |
Rollup of 12 pull requests
Successful merges:
- rust-lang/rust#156976 (enable eager `param_env` norm in new solver)
- rust-lang/rust#158537 (Add `std::io::cursor::WriteThroughCursor`)
- rust-lang/rust#158540 (Move `std::io::Seek` to `core::io`)
- rust-lang/rust#157820 (consider subtyping when checking if an infer var is sized)
- rust-lang/rust#158505 (Update POSIX edition links)
- rust-lang/rust#158853 (Fix typo for link on nto-qnx.md)
- rust-lang/rust#157466 (Better error message when bare type in impl parameter list)
- rust-lang/rust#157966 (Emit a suggestion to cast the never type into a concrete type when it fails to satisfy an `impl Trait` bound)
- rust-lang/rust#158381 (Expose debug scope of statement and terminator in rustc_public)
- rust-lang/rust#158405 (rustc_target: Add ARMv8-M related target features)
- rust-lang/rust#158770 (Weaken guarantee for `From<legacy::RangeInclusive> for RangeInclusive`)
- rust-lang/rust#158820 (Fix rustdoc ICE on deprecated note in inlined re-export chain)73 files changed, 1143 insertions(+), 725 deletions(-)
compiler/rustc_hir_analysis/src/check/compare_impl_item.rs+7-12| ... | ... | @@ -239,26 +239,21 @@ fn compare_method_predicate_entailment<'tcx>( |
| 239 | 239 | let hybrid_preds = hybrid_preds.into_iter().map(Unnormalized::skip_norm_wip); |
| 240 | 240 | let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id); |
| 241 | 241 | let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds)); |
| 242 | // FIXME(-Zhigher-ranked-assumptions): The `hybrid_preds` | |
| 242 | // NOTE(-Zhigher-ranked-assumptions): The `hybrid_preds` | |
| 243 | 243 | // should be well-formed. However, using them may result in |
| 244 | 244 | // region errors as we currently don't track placeholder |
| 245 | 245 | // assumptions. |
| 246 | 246 | // |
| 247 | // To avoid being backwards incompatible with the old solver, | |
| 248 | // we also eagerly normalize the where-bounds in the new solver | |
| 249 | // here while ignoring region constraints. This means we can then | |
| 250 | // use where-bounds whose normalization results in placeholder | |
| 251 | // errors further down without getting any errors. | |
| 247 | // We eagerly normalize the where-clauses here while ignoring | |
| 248 | // region constraints. This means we can then use where-bounds | |
| 249 | // whose normalization results in placeholder errors further | |
| 250 | // down without getting any errors. | |
| 252 | 251 | // |
| 253 | // It should be sound to do so as the only region errors here | |
| 252 | // This should be sound to do so as the only region errors here | |
| 254 | 253 | // should be due to missing implied bounds. |
| 255 | 254 | // |
| 256 | 255 | // cc trait-system-refactor-initiative/issues/166. |
| 257 | let param_env = if tcx.next_trait_solver_globally() { | |
| 258 | traits::deeply_normalize_param_env_ignoring_regions(tcx, param_env, normalize_cause) | |
| 259 | } else { | |
| 260 | traits::normalize_param_env_or_error(tcx, param_env, normalize_cause) | |
| 261 | }; | |
| 256 | let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); | |
| 262 | 257 | debug!(caller_bounds=?param_env.caller_bounds()); |
| 263 | 258 | |
| 264 | 259 | let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); |
compiler/rustc_hir_typeck/src/closure.rs+6-5| ... | ... | @@ -23,6 +23,7 @@ use rustc_trait_selection::traits; |
| 23 | 23 | use tracing::{debug, instrument, trace}; |
| 24 | 24 | |
| 25 | 25 | use super::{CoroutineTypes, Expectation, FnCtxt, check_fn}; |
| 26 | use crate::fn_ctxt::UseSubtyping; | |
| 26 | 27 | |
| 27 | 28 | /// What signature do we *expect* the closure to have from context? |
| 28 | 29 | #[derive(Debug, Clone, TypeFoldable, TypeVisitable)] |
| ... | ... | @@ -317,7 +318,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 317 | 318 | ty::Infer(ty::TyVar(vid)) => self.deduce_closure_signature_from_predicates( |
| 318 | 319 | Ty::new_var(self.tcx, self.root_var(vid)), |
| 319 | 320 | closure_kind, |
| 320 | self.obligations_for_self_ty(vid) | |
| 321 | self.obligations_for_self_ty(vid, UseSubtyping::No) | |
| 321 | 322 | .into_iter() |
| 322 | 323 | .map(|obl| (obl.predicate, obl.cause.span)), |
| 323 | 324 | ), |
| ... | ... | @@ -587,7 +588,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 587 | 588 | |
| 588 | 589 | // FIXME: We may want to elaborate here, though I assume this will be exceedingly rare. |
| 589 | 590 | let mut return_ty = None; |
| 590 | for bound in self.obligations_for_self_ty(return_vid) { | |
| 591 | for bound in self.obligations_for_self_ty(return_vid, UseSubtyping::No) { | |
| 591 | 592 | if let Some(ret_projection) = bound.predicate.as_projection_clause() |
| 592 | 593 | && let Some(ret_projection) = ret_projection.no_bound_vars() |
| 593 | 594 | && self.tcx.is_lang_item(ret_projection.def_id(), LangItem::FutureOutput) |
| ... | ... | @@ -987,9 +988,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 987 | 988 | |
| 988 | 989 | let output_ty = match *ret_ty.kind() { |
| 989 | 990 | ty::Infer(ty::TyVar(ret_vid)) => { |
| 990 | self.obligations_for_self_ty(ret_vid).into_iter().find_map(|obligation| { | |
| 991 | get_future_output(obligation.predicate, obligation.cause.span) | |
| 992 | })? | |
| 991 | self.obligations_for_self_ty(ret_vid, UseSubtyping::No).into_iter().find_map( | |
| 992 | |obligation| get_future_output(obligation.predicate, obligation.cause.span), | |
| 993 | )? | |
| 993 | 994 | } |
| 994 | 995 | ty::Alias(_, ty::AliasTy { kind: ty::Projection { .. }, .. }) => { |
| 995 | 996 | return Some(Ty::new_error_with_message( |
compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs+8-4| ... | ... | @@ -755,14 +755,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 755 | 755 | |
| 756 | 756 | pub(crate) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { |
| 757 | 757 | let sized_did = self.tcx.lang_items().sized_trait(); |
| 758 | self.obligations_for_self_ty(self_ty).into_iter().any(|obligation| { | |
| 759 | match obligation.predicate.kind().skip_binder() { | |
| 758 | ||
| 759 | // NB: `T: Sized` implies that all subtypes and all supertypes of `T` are also sized, | |
| 760 | // so it's valid to use subtyping here. (subtyping has to preserve layout and | |
| 761 | // `T <: U => &T <: &U`, so subtyping can't change sizedness) | |
| 762 | self.obligations_for_self_ty(self_ty, super::UseSubtyping::Yes).into_iter().any( | |
| 763 | |obligation| match obligation.predicate.kind().skip_binder() { | |
| 760 | 764 | ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { |
| 761 | 765 | Some(data.def_id()) == sized_did |
| 762 | 766 | } |
| 763 | 767 | _ => false, |
| 764 | } | |
| 765 | }) | |
| 768 | }, | |
| 769 | ) | |
| 766 | 770 | } |
| 767 | 771 | |
| 768 | 772 | pub(crate) fn err_args(&self, len: usize, guar: ErrorGuaranteed) -> Vec<Ty<'tcx>> { |
compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs+46-13| ... | ... | @@ -13,19 +13,38 @@ use tracing::{debug, instrument, trace}; |
| 13 | 13 | |
| 14 | 14 | use crate::FnCtxt; |
| 15 | 15 | |
| 16 | /// Whatever to use subtyping or not when inspecting obligations | |
| 17 | #[derive(Debug, Copy, Clone)] | |
| 18 | pub(crate) enum UseSubtyping { | |
| 19 | /// Do **not** use subtyping. [`FnCtxt::obligations_for_self_ty`] will only return obligations | |
| 20 | /// where the self type is known to be equal to the provided vid. | |
| 21 | No, | |
| 22 | ||
| 23 | /// Use subtyping. [`FnCtxt::obligations_for_self_ty`] will return obligations | |
| 24 | /// where the self type is related to the provided vid via subtyping. | |
| 25 | /// | |
| 26 | /// Using this requires extra care, as traits holding for a subtype or a supertype, does not | |
| 27 | /// necessarily imply that they hold for the respective supertype or subtype. | |
| 28 | Yes, | |
| 29 | } | |
| 30 | ||
| 16 | 31 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 17 | 32 | /// Returns a list of all obligations whose self type has been unified |
| 18 | 33 | /// with the unconstrained type `self_ty`. |
| 19 | 34 | #[instrument(skip(self), level = "debug")] |
| 20 | pub(crate) fn obligations_for_self_ty(&self, self_ty: ty::TyVid) -> PredicateObligations<'tcx> { | |
| 35 | pub(crate) fn obligations_for_self_ty( | |
| 36 | &self, | |
| 37 | self_ty: ty::TyVid, | |
| 38 | subtyping: UseSubtyping, | |
| 39 | ) -> PredicateObligations<'tcx> { | |
| 21 | 40 | if self.next_trait_solver() { |
| 22 | self.obligations_for_self_ty_next(self_ty) | |
| 41 | self.obligations_for_self_ty_next(self_ty, subtyping) | |
| 23 | 42 | } else { |
| 24 | let ty_var_root = self.root_var(self_ty); | |
| 25 | 43 | let mut obligations = self.fulfillment_cx.borrow().pending_obligations(); |
| 26 | 44 | trace!("pending_obligations = {:#?}", obligations); |
| 27 | obligations | |
| 28 | .retain(|obligation| self.predicate_has_self_ty(obligation.predicate, ty_var_root)); | |
| 45 | obligations.retain(|obligation| { | |
| 46 | self.predicate_has_self_ty(obligation.predicate, self_ty, subtyping) | |
| 47 | }); | |
| 29 | 48 | obligations |
| 30 | 49 | } |
| 31 | 50 | } |
| ... | ... | @@ -35,14 +54,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 35 | 54 | &self, |
| 36 | 55 | predicate: ty::Predicate<'tcx>, |
| 37 | 56 | expected_vid: ty::TyVid, |
| 57 | subtyping: UseSubtyping, | |
| 38 | 58 | ) -> bool { |
| 39 | 59 | match predicate.kind().skip_binder() { |
| 40 | 60 | ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { |
| 41 | self.type_matches_expected_vid(data.self_ty(), expected_vid) | |
| 61 | self.type_matches_expected_vid(data.self_ty(), expected_vid, subtyping) | |
| 42 | 62 | } |
| 43 | 63 | ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { |
| 44 | 64 | if data.projection_term.kind.is_trait_projection() { |
| 45 | self.type_matches_expected_vid(data.self_ty(), expected_vid) | |
| 65 | self.type_matches_expected_vid(data.self_ty(), expected_vid, subtyping) | |
| 46 | 66 | } else { |
| 47 | 67 | false |
| 48 | 68 | } |
| ... | ... | @@ -64,14 +84,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 64 | 84 | } |
| 65 | 85 | |
| 66 | 86 | #[instrument(level = "debug", skip(self), ret)] |
| 67 | fn type_matches_expected_vid(&self, ty: Ty<'tcx>, expected_vid: ty::TyVid) -> bool { | |
| 87 | fn type_matches_expected_vid( | |
| 88 | &self, | |
| 89 | ty: Ty<'tcx>, | |
| 90 | expected_vid: ty::TyVid, | |
| 91 | subtyping: UseSubtyping, | |
| 92 | ) -> bool { | |
| 68 | 93 | let ty = self.shallow_resolve(ty); |
| 69 | 94 | debug!(?ty); |
| 70 | 95 | |
| 71 | 96 | match *ty.kind() { |
| 72 | ty::Infer(ty::TyVar(found_vid)) => { | |
| 73 | self.root_var(expected_vid) == self.root_var(found_vid) | |
| 74 | } | |
| 97 | ty::Infer(ty::TyVar(found_vid)) => match subtyping { | |
| 98 | UseSubtyping::No => self.root_var(expected_vid) == self.root_var(found_vid), | |
| 99 | UseSubtyping::Yes => { | |
| 100 | self.sub_unification_table_root_var(expected_vid) | |
| 101 | == self.sub_unification_table_root_var(found_vid) | |
| 102 | } | |
| 103 | }, | |
| 75 | 104 | _ => false, |
| 76 | 105 | } |
| 77 | 106 | } |
| ... | ... | @@ -79,6 +108,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 79 | 108 | pub(crate) fn obligations_for_self_ty_next( |
| 80 | 109 | &self, |
| 81 | 110 | self_ty: ty::TyVid, |
| 111 | subtyping: UseSubtyping, | |
| 82 | 112 | ) -> PredicateObligations<'tcx> { |
| 83 | 113 | // We only look at obligations which may reference the self type. |
| 84 | 114 | // This lookup uses the `sub_root` instead of the inference variable |
| ... | ... | @@ -93,6 +123,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 93 | 123 | .borrow() |
| 94 | 124 | .pending_obligations_potentially_referencing_sub_root(&self.infcx, sub_root_var); |
| 95 | 125 | debug!(?obligations); |
| 126 | ||
| 96 | 127 | let mut obligations_for_self_ty = PredicateObligations::new(); |
| 97 | 128 | for obligation in obligations { |
| 98 | 129 | let mut visitor = NestedObligationsForSelfTy { |
| ... | ... | @@ -100,6 +131,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 100 | 131 | self_ty, |
| 101 | 132 | obligations_for_self_ty: &mut obligations_for_self_ty, |
| 102 | 133 | root_cause: &obligation.cause, |
| 134 | subtyping, | |
| 103 | 135 | }; |
| 104 | 136 | |
| 105 | 137 | let goal = obligation.as_goal(); |
| ... | ... | @@ -182,6 +214,7 @@ struct NestedObligationsForSelfTy<'a, 'tcx> { |
| 182 | 214 | self_ty: ty::TyVid, |
| 183 | 215 | root_cause: &'a ObligationCause<'tcx>, |
| 184 | 216 | obligations_for_self_ty: &'a mut PredicateObligations<'tcx>, |
| 217 | subtyping: UseSubtyping, | |
| 185 | 218 | } |
| 186 | 219 | |
| 187 | 220 | impl<'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'_, 'tcx> { |
| ... | ... | @@ -209,7 +242,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'_, 'tcx> { |
| 209 | 242 | .orig_values() |
| 210 | 243 | .iter() |
| 211 | 244 | .filter_map(|arg| arg.as_type()) |
| 212 | .any(|ty| self.fcx.type_matches_expected_vid(ty, self.self_ty)) | |
| 245 | .any(|ty| self.fcx.type_matches_expected_vid(ty, self.self_ty, self.subtyping)) | |
| 213 | 246 | { |
| 214 | 247 | debug!(goal = ?inspect_goal.goal(), "goal does not mention self type"); |
| 215 | 248 | return; |
| ... | ... | @@ -217,7 +250,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'_, 'tcx> { |
| 217 | 250 | |
| 218 | 251 | let tcx = self.fcx.tcx; |
| 219 | 252 | let goal = inspect_goal.goal(); |
| 220 | if self.fcx.predicate_has_self_ty(goal.predicate, self.self_ty) { | |
| 253 | if self.fcx.predicate_has_self_ty(goal.predicate, self.self_ty, self.subtyping) { | |
| 221 | 254 | self.obligations_for_self_ty.push(traits::Obligation::new( |
| 222 | 255 | tcx, |
| 223 | 256 | self.root_cause.clone(), |
compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs+1| ... | ... | @@ -8,6 +8,7 @@ mod suggestions; |
| 8 | 8 | use std::cell::{Cell, RefCell}; |
| 9 | 9 | use std::ops::Deref; |
| 10 | 10 | |
| 11 | pub(crate) use inspect_obligations::UseSubtyping; | |
| 11 | 12 | use rustc_errors::DiagCtxtHandle; |
| 12 | 13 | use rustc_hir::attrs::{DivergingBlockBehavior, DivergingFallbackBehavior}; |
| 13 | 14 | use rustc_hir::def_id::{DefId, LocalDefId}; |
compiler/rustc_infer/src/infer/type_variable.rs+3-5| ... | ... | @@ -246,13 +246,11 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { |
| 246 | 246 | } |
| 247 | 247 | |
| 248 | 248 | /// Returns the "root" variable of `vid` in the `sub_unification_table` |
| 249 | /// equivalence table. All type variables that have been are related via | |
| 249 | /// equivalence table. All type variables that have been related via | |
| 250 | 250 | /// equality or subtyping will yield the same root variable (per the |
| 251 | 251 | /// union-find algorithm), so `sub_unification_table_root_var(a) |
| 252 | /// == sub_unification_table_root_var(b)` implies that: | |
| 253 | /// ```text | |
| 254 | /// exists X. (a <: X || X <: a) && (b <: X || X <: b) | |
| 255 | /// ``` | |
| 252 | /// == sub_unification_table_root_var(b)` implies that `a` and `b` are | |
| 253 | /// transitively related via subtyping. | |
| 256 | 254 | pub(crate) fn sub_unification_table_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { |
| 257 | 255 | self.sub_unification_table().find(vid).vid |
| 258 | 256 | } |
compiler/rustc_parse/src/errors.rs+30| ... | ... | @@ -4660,3 +4660,33 @@ pub(crate) struct UseRegularStructSuggestion { |
| 4660 | 4660 | #[suggestion_part(code = "")] |
| 4661 | 4661 | pub semicolon: Option<Span>, |
| 4662 | 4662 | } |
| 4663 | #[derive(Diagnostic)] | |
| 4664 | #[diag("expected type parameter, found path `{$path}`")] | |
| 4665 | pub(crate) struct FoundPathInGenerics { | |
| 4666 | #[primary_span] | |
| 4667 | pub span: Span, | |
| 4668 | pub path: String, | |
| 4669 | } | |
| 4670 | #[derive(Subdiagnostic)] | |
| 4671 | #[suggestion( | |
| 4672 | "you might have meant to bind a type parameter to a trait", | |
| 4673 | applicability = "maybe-incorrect", | |
| 4674 | code = "T: " | |
| 4675 | )] | |
| 4676 | ||
| 4677 | pub(crate) struct SuggestBindTypeParameter { | |
| 4678 | #[primary_span] | |
| 4679 | pub span: Span, | |
| 4680 | } | |
| 4681 | ||
| 4682 | #[derive(Subdiagnostic)] | |
| 4683 | #[suggestion( | |
| 4684 | "alternatively, you might have meant to introduce type parameter", | |
| 4685 | applicability = "maybe-incorrect", | |
| 4686 | code = "{parameters}" | |
| 4687 | )] | |
| 4688 | pub(crate) struct SuggestIntroduceTypeParameter { | |
| 4689 | #[primary_span] | |
| 4690 | pub span: Span, | |
| 4691 | pub parameters: String, | |
| 4692 | } |
compiler/rustc_parse/src/parser/diagnostics.rs+55-9| ... | ... | @@ -6,7 +6,7 @@ use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind}; |
| 6 | 6 | use rustc_ast::util::parser::AssocOp; |
| 7 | 7 | use rustc_ast::{ |
| 8 | 8 | self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, |
| 9 | Block, BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, | |
| 9 | Block, BlockCheckMode, Expr, ExprKind, GenericArg, GenericArgs, Generics, Item, ItemKind, | |
| 10 | 10 | MgcaDisambiguation, Param, Pat, PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind, |
| 11 | 11 | }; |
| 12 | 12 | use rustc_ast_pretty::pprust; |
| ... | ... | @@ -31,14 +31,16 @@ use crate::errors::{ |
| 31 | 31 | AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, |
| 32 | 32 | ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, |
| 33 | 33 | DocCommentDoesNotDocumentAnything, DocCommentOnParamType, DoubleColonInBound, |
| 34 | ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets, | |
| 35 | GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, HelpUseLatestEdition, | |
| 36 | InInTypo, IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, | |
| 37 | MisspelledKw, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, | |
| 38 | SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, | |
| 39 | SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, | |
| 40 | TernaryOperatorSuggestion, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, | |
| 41 | UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType, | |
| 34 | ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, FoundPathInGenerics, | |
| 35 | GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, | |
| 36 | HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait, | |
| 37 | IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, MisspelledKw, | |
| 38 | PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, | |
| 39 | StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, | |
| 40 | SuggEscapeIdentifier, SuggRemoveComma, SuggestBindTypeParameter, SuggestIntroduceTypeParameter, | |
| 41 | TernaryOperator, TernaryOperatorSuggestion, UnexpectedConstInGenericParam, | |
| 42 | UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, | |
| 43 | UseEqInstead, WrapType, | |
| 42 | 44 | }; |
| 43 | 45 | use crate::exp; |
| 44 | 46 | use crate::parser::FnContext; |
| ... | ... | @@ -3164,4 +3166,48 @@ impl<'a> Parser<'a> { |
| 3164 | 3166 | } |
| 3165 | 3167 | Ok(()) |
| 3166 | 3168 | } |
| 3169 | pub(super) fn maybe_type_in_generic_parameter(&mut self, origin_error: Diag<'a>) -> Diag<'a> { | |
| 3170 | if !self.may_recover() { | |
| 3171 | return origin_error; | |
| 3172 | } | |
| 3173 | self.with_recovery(super::Recovery::Forbidden, |snapshot| { | |
| 3174 | snapshot.bump(); | |
| 3175 | let lo = snapshot.token.span.shrink_to_lo(); | |
| 3176 | ||
| 3177 | let ty = match snapshot.parse_ty() { | |
| 3178 | Ok(t) => t, | |
| 3179 | Err(err) => { | |
| 3180 | err.cancel(); | |
| 3181 | return origin_error; | |
| 3182 | } | |
| 3183 | }; | |
| 3184 | let TyKind::Path(_, path) = ty.kind else { | |
| 3185 | return origin_error; | |
| 3186 | }; | |
| 3187 | let Some(GenericArgs::AngleBracketed(AngleBracketedArgs { span: _, ref args })) = | |
| 3188 | path.segments[0].args | |
| 3189 | else { | |
| 3190 | return origin_error; | |
| 3191 | }; | |
| 3192 | ||
| 3193 | let path_span = path.span; | |
| 3194 | let mut new_error = snapshot.dcx().create_err(FoundPathInGenerics { | |
| 3195 | span: path_span, | |
| 3196 | path: snapshot.span_to_snippet(path_span).unwrap(), | |
| 3197 | }); | |
| 3198 | new_error.subdiagnostic(SuggestBindTypeParameter { span: lo }); | |
| 3199 | origin_error.cancel(); | |
| 3200 | ||
| 3201 | let params = args | |
| 3202 | .iter() | |
| 3203 | .map(|arg| snapshot.span_to_snippet(arg.span()).unwrap()) | |
| 3204 | .collect::<Vec<_>>() | |
| 3205 | .join(", "); | |
| 3206 | new_error.subdiagnostic(SuggestIntroduceTypeParameter { | |
| 3207 | span: path_span, | |
| 3208 | parameters: params, | |
| 3209 | }); | |
| 3210 | new_error | |
| 3211 | }) | |
| 3212 | } | |
| 3167 | 3213 | } |
compiler/rustc_parse/src/parser/item.rs+16-3| ... | ... | @@ -662,11 +662,20 @@ impl<'a> Parser<'a> { |
| 662 | 662 | let constness = self.parse_constness(Case::Sensitive); |
| 663 | 663 | let safety = self.parse_safety(Case::Sensitive); |
| 664 | 664 | self.expect_keyword(exp!(Impl))?; |
| 665 | ||
| 665 | let mut generics_snapshot = None; | |
| 666 | 666 | // First, parse generic parameters if necessary. |
| 667 | 667 | let mut generics = if self.choose_generics_over_qpath(0) { |
| 668 | 668 | self.parse_generics()? |
| 669 | 669 | } else { |
| 670 | // We might be mistakenly trying to use a generic type as a generic parameter. | |
| 671 | // impl<X<T>> Trait for Y<T> { ... } | |
| 672 | if self.look_ahead(0, |t| t == &token::Lt) | |
| 673 | && self.look_ahead(1, |t| t.is_ident()) | |
| 674 | && self.look_ahead(2, |t| t == &token::Lt) | |
| 675 | { | |
| 676 | generics_snapshot = Some(self.create_snapshot_for_diagnostic()); | |
| 677 | } | |
| 678 | ||
| 670 | 679 | let mut generics = Generics::default(); |
| 671 | 680 | // impl A for B {} |
| 672 | 681 | // /\ this is where `generics.span` should point when there are no type params. |
| ... | ... | @@ -698,9 +707,13 @@ impl<'a> Parser<'a> { |
| 698 | 707 | for_span: span.to(self.token.span), |
| 699 | 708 | })); |
| 700 | 709 | } else { |
| 701 | self.parse_ty_with_generics_recovery(&generics)? | |
| 710 | self.parse_ty_with_generics_recovery(&generics).map_err(|e| { | |
| 711 | let Some(mut snapshot) = generics_snapshot else { | |
| 712 | return e; | |
| 713 | }; | |
| 714 | snapshot.maybe_type_in_generic_parameter(e) | |
| 715 | })? | |
| 702 | 716 | }; |
| 703 | ||
| 704 | 717 | // If `for` is missing we try to recover. |
| 705 | 718 | let has_for = self.eat_keyword(exp!(For)); |
| 706 | 719 | let missing_for_span = self.prev_token.span.between(self.token.span); |
compiler/rustc_public/src/mir/body.rs+2-2| ... | ... | @@ -139,7 +139,7 @@ pub struct BasicBlock { |
| 139 | 139 | #[derive(Clone, Debug, Eq, PartialEq, Serialize)] |
| 140 | 140 | pub struct Terminator { |
| 141 | 141 | pub kind: TerminatorKind, |
| 142 | pub span: Span, | |
| 142 | pub source_info: SourceInfo, | |
| 143 | 143 | } |
| 144 | 144 | |
| 145 | 145 | impl Terminator { |
| ... | ... | @@ -468,7 +468,7 @@ pub enum NonDivergingIntrinsic { |
| 468 | 468 | #[derive(Clone, Debug, Eq, PartialEq, Serialize)] |
| 469 | 469 | pub struct Statement { |
| 470 | 470 | pub kind: StatementKind, |
| 471 | pub span: Span, | |
| 471 | pub source_info: SourceInfo, | |
| 472 | 472 | } |
| 473 | 473 | |
| 474 | 474 | #[derive(Clone, Debug, Eq, PartialEq, Serialize)] |
compiler/rustc_public/src/mir/visit.rs+8-8| ... | ... | @@ -139,9 +139,9 @@ macro_rules! make_mir_visitor { |
| 139 | 139 | fn super_basic_block(&mut self, bb: &$($mutability)? BasicBlock) { |
| 140 | 140 | let BasicBlock { statements, terminator } = bb; |
| 141 | 141 | for stmt in statements { |
| 142 | self.visit_statement(stmt, Location(stmt.span)); | |
| 142 | self.visit_statement(stmt, Location(stmt.source_info.span)); | |
| 143 | 143 | } |
| 144 | self.visit_terminator(terminator, Location(terminator.span)); | |
| 144 | self.visit_terminator(terminator, Location(terminator.source_info.span)); | |
| 145 | 145 | } |
| 146 | 146 | |
| 147 | 147 | fn super_local_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { |
| ... | ... | @@ -159,8 +159,8 @@ macro_rules! make_mir_visitor { |
| 159 | 159 | } |
| 160 | 160 | |
| 161 | 161 | fn super_statement(&mut self, stmt: &$($mutability)? Statement, location: Location) { |
| 162 | let Statement { kind, span } = stmt; | |
| 163 | self.visit_span(span); | |
| 162 | let Statement { kind, source_info } = stmt; | |
| 163 | self.visit_span(&$($mutability)? source_info.span); | |
| 164 | 164 | match kind { |
| 165 | 165 | StatementKind::Assign(place, rvalue) => { |
| 166 | 166 | self.visit_place(place, PlaceContext::MUTATING, location); |
| ... | ... | @@ -199,8 +199,8 @@ macro_rules! make_mir_visitor { |
| 199 | 199 | } |
| 200 | 200 | |
| 201 | 201 | fn super_terminator(&mut self, term: &$($mutability)? Terminator, location: Location) { |
| 202 | let Terminator { kind, span } = term; | |
| 203 | self.visit_span(span); | |
| 202 | let Terminator { kind, source_info } = term; | |
| 203 | self.visit_span(&$($mutability)? source_info.span); | |
| 204 | 204 | match kind { |
| 205 | 205 | TerminatorKind::Goto { .. } |
| 206 | 206 | | TerminatorKind::Resume |
| ... | ... | @@ -540,7 +540,7 @@ impl Location { |
| 540 | 540 | pub fn statement_location(body: &Body, bb_idx: &BasicBlockIdx, stmt_idx: usize) -> Location { |
| 541 | 541 | let bb = &body.blocks[*bb_idx]; |
| 542 | 542 | let stmt = &bb.statements[stmt_idx]; |
| 543 | Location(stmt.span) | |
| 543 | Location(stmt.source_info.span) | |
| 544 | 544 | } |
| 545 | 545 | |
| 546 | 546 | /// Location of the terminator for a given basic block. Assumes that `bb_idx` is valid for a given |
| ... | ... | @@ -548,7 +548,7 @@ pub fn statement_location(body: &Body, bb_idx: &BasicBlockIdx, stmt_idx: usize) |
| 548 | 548 | pub fn terminator_location(body: &Body, bb_idx: &BasicBlockIdx) -> Location { |
| 549 | 549 | let bb = &body.blocks[*bb_idx]; |
| 550 | 550 | let terminator = &bb.terminator; |
| 551 | Location(terminator.span) | |
| 551 | Location(terminator.source_info.span) | |
| 552 | 552 | } |
| 553 | 553 | |
| 554 | 554 | /// Reference to a place used to represent a partial projection. |
compiler/rustc_public/src/unstable/convert/stable/mir.rs+2-2| ... | ... | @@ -74,7 +74,7 @@ impl<'tcx> Stable<'tcx> for mir::Statement<'tcx> { |
| 74 | 74 | ) -> Self::T { |
| 75 | 75 | Statement { |
| 76 | 76 | kind: self.kind.stable(tables, cx), |
| 77 | span: self.source_info.span.stable(tables, cx), | |
| 77 | source_info: self.source_info.stable(tables, cx), | |
| 78 | 78 | } |
| 79 | 79 | } |
| 80 | 80 | } |
| ... | ... | @@ -695,7 +695,7 @@ impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> { |
| 695 | 695 | use crate::mir::Terminator; |
| 696 | 696 | Terminator { |
| 697 | 697 | kind: self.kind.stable(tables, cx), |
| 698 | span: self.source_info.span.stable(tables, cx), | |
| 698 | source_info: self.source_info.stable(tables, cx), | |
| 699 | 699 | } |
| 700 | 700 | } |
| 701 | 701 | } |
compiler/rustc_target/src/target_features.rs+9-3| ... | ... | @@ -153,6 +153,7 @@ type ImpliedFeatures = &'static [&'static str]; |
| 153 | 153 | static ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ |
| 154 | 154 | // tidy-alphabetical-start |
| 155 | 155 | ("aclass", Unstable(sym::arm_target_feature), &[]), |
| 156 | ("acquire-release", Unstable(sym::arm_target_feature), &[]), | |
| 156 | 157 | ("aes", Unstable(sym::arm_target_feature), &["neon"]), |
| 157 | 158 | ( |
| 158 | 159 | "atomics-32", |
| ... | ... | @@ -171,6 +172,8 @@ static ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ |
| 171 | 172 | ("fpregs", Unstable(sym::arm_target_feature), &[]), |
| 172 | 173 | ("i8mm", Unstable(sym::arm_target_feature), &["neon"]), |
| 173 | 174 | ("mclass", Unstable(sym::arm_target_feature), &[]), |
| 175 | ("mve", Unstable(sym::arm_target_feature), &["v8.1m.main", "dsp", "fpregs"]), | |
| 176 | ("mve.fp", Unstable(sym::arm_target_feature), &["mve"]), | |
| 174 | 177 | ("neon", Unstable(sym::arm_target_feature), &["vfp3"]), |
| 175 | 178 | ("rclass", Unstable(sym::arm_target_feature), &[]), |
| 176 | 179 | ("sha2", Unstable(sym::arm_target_feature), &["neon"]), |
| ... | ... | @@ -188,9 +191,13 @@ static ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ |
| 188 | 191 | ("v5te", Unstable(sym::arm_target_feature), &[]), |
| 189 | 192 | ("v6", Unstable(sym::arm_target_feature), &["v5te"]), |
| 190 | 193 | ("v6k", Unstable(sym::arm_target_feature), &["v6"]), |
| 191 | ("v6t2", Unstable(sym::arm_target_feature), &["v6k", "thumb2"]), | |
| 194 | ("v6m", Unstable(sym::arm_target_feature), &["v6"]), | |
| 195 | ("v6t2", Unstable(sym::arm_target_feature), &["v6k", "v8m", "thumb2"]), | |
| 192 | 196 | ("v7", Unstable(sym::arm_target_feature), &["v6t2"]), |
| 193 | 197 | ("v8", Unstable(sym::arm_target_feature), &["v7"]), |
| 198 | ("v8.1m.main", Unstable(sym::arm_target_feature), &["v8m.main"]), | |
| 199 | ("v8m", Unstable(sym::arm_target_feature), &["v6m"]), | |
| 200 | ("v8m.main", Unstable(sym::arm_target_feature), &["v7"]), | |
| 194 | 201 | ("vfp2", Unstable(sym::arm_target_feature), &[]), |
| 195 | 202 | ("vfp3", Unstable(sym::arm_target_feature), &["vfp2", "d32"]), |
| 196 | 203 | ("vfp4", Unstable(sym::arm_target_feature), &["vfp3"]), |
| ... | ... | @@ -1073,9 +1080,8 @@ const X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static |
| 1073 | 1080 | const AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = |
| 1074 | 1081 | &[(128, "neon")]; |
| 1075 | 1082 | |
| 1076 | // We might want to add "helium" too. | |
| 1077 | 1083 | const ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = |
| 1078 | &[(128, "neon")]; | |
| 1084 | &[(128, "neon"), (128, "mve")]; | |
| 1079 | 1085 | |
| 1080 | 1086 | const AMDGPU_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = |
| 1081 | 1087 | &[(1024, "")]; |
compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs+14-3| ... | ... | @@ -4479,7 +4479,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { |
| 4479 | 4479 | } |
| 4480 | 4480 | ObligationCauseCode::OpaqueReturnType(expr_info) => { |
| 4481 | 4481 | let (expr_ty, expr) = if let Some((expr_ty, hir_id)) = expr_info { |
| 4482 | let expr_ty = tcx.short_string(expr_ty, err.long_ty_path()); | |
| 4483 | 4482 | let expr = tcx.hir_expect_expr(hir_id); |
| 4484 | 4483 | (expr_ty, expr) |
| 4485 | 4484 | } else if let Some(body_id) = tcx.hir_node_by_def_id(body_id).body_id() |
| ... | ... | @@ -4494,15 +4493,27 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { |
| 4494 | 4493 | && let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder() |
| 4495 | 4494 | && self.can_eq(param_env, pred.self_ty(), expr_ty) |
| 4496 | 4495 | { |
| 4497 | let expr_ty = tcx.short_string(expr_ty, err.long_ty_path()); | |
| 4498 | 4496 | (expr_ty, expr) |
| 4499 | 4497 | } else { |
| 4500 | 4498 | return; |
| 4501 | 4499 | }; |
| 4500 | let expr_ty_string = tcx.short_string(expr_ty, err.long_ty_path()); | |
| 4501 | if expr_ty.is_never() | |
| 4502 | && let span = expr.span.source_callsite() | |
| 4503 | && let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) | |
| 4504 | && span != expr.span | |
| 4505 | { | |
| 4506 | err.span_suggestion( | |
| 4507 | span, | |
| 4508 | "`!` can be coerced to any type; consider casting it to a concrete type that implements the trait", | |
| 4509 | format!("{snippet} as /* Type */"), | |
| 4510 | Applicability::HasPlaceholders, | |
| 4511 | ); | |
| 4512 | } | |
| 4502 | 4513 | err.span_label( |
| 4503 | 4514 | expr.span, |
| 4504 | 4515 | with_forced_trimmed_paths!(format!( |
| 4505 | "return type was inferred to be `{expr_ty}` here", | |
| 4516 | "return type was inferred to be `{expr_ty_string}` here", | |
| 4506 | 4517 | )), |
| 4507 | 4518 | ); |
| 4508 | 4519 | suggest_remove_deref(err, &expr); |
compiler/rustc_trait_selection/src/traits/mod.rs+11-78| ... | ... | @@ -30,7 +30,6 @@ use rustc_errors::ErrorGuaranteed; |
| 30 | 30 | pub use rustc_infer::traits::*; |
| 31 | 31 | use rustc_macros::TypeVisitable; |
| 32 | 32 | use rustc_middle::query::Providers; |
| 33 | use rustc_middle::span_bug; | |
| 34 | 33 | use rustc_middle::ty::error::{ExpectedFound, TypeError}; |
| 35 | 34 | use rustc_middle::ty::{ |
| 36 | 35 | self, Clause, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder, |
| ... | ... | @@ -257,12 +256,6 @@ fn do_normalize_predicates<'tcx>( |
| 257 | 256 | elaborated_env: ty::ParamEnv<'tcx>, |
| 258 | 257 | predicates: Vec<ty::Clause<'tcx>>, |
| 259 | 258 | ) -> Result<Vec<ty::Clause<'tcx>>, ErrorGuaranteed> { |
| 260 | // Even if we move back to eager normalization elsewhere, | |
| 261 | // param env normalization remains lazy in the next solver. | |
| 262 | if tcx.next_trait_solver_globally() { | |
| 263 | return Ok(predicates); | |
| 264 | } | |
| 265 | ||
| 266 | 259 | // FIXME. We should really... do something with these region |
| 267 | 260 | // obligations. But this call just continues the older |
| 268 | 261 | // behavior (i.e., doesn't cause any new bugs), and it would |
| ... | ... | @@ -294,17 +287,20 @@ fn do_normalize_predicates<'tcx>( |
| 294 | 287 | |
| 295 | 288 | // We can use the `elaborated_env` here; the region code only |
| 296 | 289 | // cares about declarations like `'a: 'b`. |
| 290 | // | |
| 297 | 291 | // FIXME: It's very weird that we ignore region obligations but apparently |
| 298 | 292 | // still need to use `resolve_regions` as we need the resolved regions in |
| 299 | 293 | // the normalized predicates. |
| 300 | let errors = infcx.resolve_regions(cause.body_id, elaborated_env, []); | |
| 301 | if !errors.is_empty() { | |
| 302 | tcx.dcx().span_delayed_bug( | |
| 303 | span, | |
| 304 | format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"), | |
| 305 | ); | |
| 306 | } | |
| 307 | ||
| 294 | // | |
| 295 | // FIXME(-Zhigher-ranked-assumptions): We're ignoring region errors for now. | |
| 296 | // There're placeholder constraints `leaking` out. This is a hack to work around | |
| 297 | // the fact that we don't support placeholder assumptions right now and is necessary | |
| 298 | // for `compare_method_predicate_entailment`. We should remove this once we | |
| 299 | // have proper support for implied bounds on binders. | |
| 300 | // | |
| 301 | // This is required by trait-system-refactor-initiative#166. The new solver encounters | |
| 302 | // this more frequently as we entirely ignore outlives predicates with the old solver. | |
| 303 | let _errors = infcx.resolve_regions(cause.body_id, elaborated_env, []); | |
| 308 | 304 | match infcx.fully_resolve(predicates) { |
| 309 | 305 | Ok(predicates) => Ok(predicates), |
| 310 | 306 | Err(fixup_err) => { |
| ... | ... | @@ -481,69 +477,6 @@ pub fn normalize_param_env_or_error<'tcx>( |
| 481 | 477 | ty::ParamEnv::new(tcx.mk_clauses(&predicates)) |
| 482 | 478 | } |
| 483 | 479 | |
| 484 | /// Deeply normalize the param env using the next solver ignoring | |
| 485 | /// region errors. | |
| 486 | /// | |
| 487 | /// FIXME(-Zhigher-ranked-assumptions): this is a hack to work around | |
| 488 | /// the fact that we don't support placeholder assumptions right now | |
| 489 | /// and is necessary for `compare_method_predicate_entailment`, see the | |
| 490 | /// use of this function for more info. We should remove this once we | |
| 491 | /// have proper support for implied bounds on binders. | |
| 492 | #[instrument(level = "debug", skip(tcx))] | |
| 493 | pub fn deeply_normalize_param_env_ignoring_regions<'tcx>( | |
| 494 | tcx: TyCtxt<'tcx>, | |
| 495 | unnormalized_env: ty::ParamEnv<'tcx>, | |
| 496 | cause: ObligationCause<'tcx>, | |
| 497 | ) -> ty::ParamEnv<'tcx> { | |
| 498 | let predicates: Vec<_> = | |
| 499 | util::elaborate(tcx, unnormalized_env.caller_bounds().into_iter()).collect(); | |
| 500 | ||
| 501 | debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); | |
| 502 | ||
| 503 | let elaborated_env = ty::ParamEnv::new(tcx.mk_clauses(&predicates)); | |
| 504 | if !elaborated_env.has_aliases() { | |
| 505 | return elaborated_env; | |
| 506 | } | |
| 507 | ||
| 508 | let span = cause.span; | |
| 509 | let infcx = tcx | |
| 510 | .infer_ctxt() | |
| 511 | .with_next_trait_solver(true) | |
| 512 | .ignoring_regions() | |
| 513 | .build(TypingMode::non_body_analysis()); | |
| 514 | let predicates = match crate::solve::deeply_normalize::<_, FulfillmentError<'tcx>>( | |
| 515 | infcx.at(&cause, elaborated_env), | |
| 516 | Unnormalized::new_wip(predicates), | |
| 517 | ) { | |
| 518 | Ok(predicates) => predicates, | |
| 519 | Err(errors) => { | |
| 520 | infcx.err_ctxt().report_fulfillment_errors(errors); | |
| 521 | // An unnormalized env is better than nothing. | |
| 522 | debug!("normalize_param_env_or_error: errored resolving predicates"); | |
| 523 | return elaborated_env; | |
| 524 | } | |
| 525 | }; | |
| 526 | ||
| 527 | debug!("do_normalize_predicates: normalized predicates = {:?}", predicates); | |
| 528 | // FIXME(-Zhigher-ranked-assumptions): We're ignoring region errors for now. | |
| 529 | // There're placeholder constraints `leaking` out. | |
| 530 | // See the fixme in the enclosing function's docs for more. | |
| 531 | let _errors = infcx.resolve_regions(cause.body_id, elaborated_env, []); | |
| 532 | ||
| 533 | let predicates = match infcx.fully_resolve(predicates) { | |
| 534 | Ok(predicates) => predicates, | |
| 535 | Err(fixup_err) => { | |
| 536 | span_bug!( | |
| 537 | span, | |
| 538 | "inference variables in normalized parameter environment: {}", | |
| 539 | fixup_err | |
| 540 | ) | |
| 541 | } | |
| 542 | }; | |
| 543 | debug!("normalize_param_env_or_error: final predicates={:?}", predicates); | |
| 544 | ty::ParamEnv::new(tcx.mk_clauses(&predicates)) | |
| 545 | } | |
| 546 | ||
| 547 | 480 | #[derive(Debug)] |
| 548 | 481 | pub enum EvaluateConstErr { |
| 549 | 482 | /// The constant being evaluated was either a generic parameter or inference variable, *or*, |
library/alloc/src/io/impls.rs+64-1| ... | ... | @@ -1,5 +1,7 @@ |
| 1 | 1 | use crate::boxed::Box; |
| 2 | use crate::io::SizeHint; | |
| 2 | use crate::io::{self, Seek, SeekFrom, SizeHint}; | |
| 3 | #[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] | |
| 4 | use crate::sync::Arc; | |
| 3 | 5 | |
| 4 | 6 | // ============================================================================= |
| 5 | 7 | // Forwarding implementations |
| ... | ... | @@ -18,5 +20,66 @@ impl<T> SizeHint for Box<T> { |
| 18 | 20 | } |
| 19 | 21 | } |
| 20 | 22 | |
| 23 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 24 | impl<S: Seek + ?Sized> Seek for Box<S> { | |
| 25 | #[inline] | |
| 26 | fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { | |
| 27 | (**self).seek(pos) | |
| 28 | } | |
| 29 | ||
| 30 | #[inline] | |
| 31 | fn rewind(&mut self) -> io::Result<()> { | |
| 32 | (**self).rewind() | |
| 33 | } | |
| 34 | ||
| 35 | #[inline] | |
| 36 | fn stream_len(&mut self) -> io::Result<u64> { | |
| 37 | (**self).stream_len() | |
| 38 | } | |
| 39 | ||
| 40 | #[inline] | |
| 41 | fn stream_position(&mut self) -> io::Result<u64> { | |
| 42 | (**self).stream_position() | |
| 43 | } | |
| 44 | ||
| 45 | #[inline] | |
| 46 | fn seek_relative(&mut self, offset: i64) -> io::Result<()> { | |
| 47 | (**self).seek_relative(offset) | |
| 48 | } | |
| 49 | } | |
| 50 | ||
| 21 | 51 | // ============================================================================= |
| 22 | 52 | // In-memory buffer implementations |
| 53 | ||
| 54 | #[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] | |
| 55 | #[stable(feature = "io_traits_arc", since = "1.73.0")] | |
| 56 | impl<S: Seek + ?Sized> Seek for Arc<S> | |
| 57 | where | |
| 58 | for<'a> &'a S: Seek, | |
| 59 | S: crate::io::IoHandle, | |
| 60 | { | |
| 61 | #[inline] | |
| 62 | fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { | |
| 63 | (&**self).seek(pos) | |
| 64 | } | |
| 65 | ||
| 66 | #[inline] | |
| 67 | fn rewind(&mut self) -> io::Result<()> { | |
| 68 | (&**self).rewind() | |
| 69 | } | |
| 70 | ||
| 71 | #[inline] | |
| 72 | fn stream_len(&mut self) -> io::Result<u64> { | |
| 73 | (&**self).stream_len() | |
| 74 | } | |
| 75 | ||
| 76 | #[inline] | |
| 77 | fn stream_position(&mut self) -> io::Result<u64> { | |
| 78 | (&**self).stream_position() | |
| 79 | } | |
| 80 | ||
| 81 | #[inline] | |
| 82 | fn seek_relative(&mut self, offset: i64) -> io::Result<()> { | |
| 83 | (&**self).seek_relative(offset) | |
| 84 | } | |
| 85 | } |
library/alloc/src/io/mod.rs+3-3| ... | ... | @@ -13,9 +13,9 @@ pub use core::io::const_error; |
| 13 | 13 | pub use core::io::{BorrowedBuf, BorrowedCursor}; |
| 14 | 14 | #[unstable(feature = "alloc_io", issue = "154046")] |
| 15 | 15 | pub use core::io::{ |
| 16 | Chain, Cursor, Empty, Error, ErrorKind, IoSlice, IoSliceMut, Repeat, Result, Sink, Take, empty, | |
| 17 | repeat, sink, | |
| 16 | Chain, Cursor, Empty, Error, ErrorKind, IoSlice, IoSliceMut, Repeat, Result, Seek, SeekFrom, | |
| 17 | Sink, Take, empty, repeat, sink, | |
| 18 | 18 | }; |
| 19 | 19 | #[doc(hidden)] |
| 20 | 20 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] |
| 21 | pub use core::io::{IoHandle, OsFunctions, SizeHint, chain, take}; | |
| 21 | pub use core::io::{IoHandle, OsFunctions, SizeHint, chain, stream_len_default, take}; |
library/alloc/src/lib.rs+1| ... | ... | @@ -155,6 +155,7 @@ |
| 155 | 155 | #![feature(ptr_metadata)] |
| 156 | 156 | #![feature(raw_os_error_ty)] |
| 157 | 157 | #![feature(rev_into_inner)] |
| 158 | #![feature(seek_stream_len)] | |
| 158 | 159 | #![feature(set_ptr_value)] |
| 159 | 160 | #![feature(share_trait)] |
| 160 | 161 | #![feature(sized_type_properties)] |
library/core/src/ascii/ascii_char.rs+2-2| ... | ... | @@ -1049,8 +1049,8 @@ impl AsciiChar { |
| 1049 | 1049 | /// before using this function. |
| 1050 | 1050 | /// |
| 1051 | 1051 | /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace |
| 1052 | /// [pct]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 | |
| 1053 | /// [bfs]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 | |
| 1052 | /// [pct]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap07.html#tag_07_03_01 | |
| 1053 | /// [bfs]: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_06_05 | |
| 1054 | 1054 | /// |
| 1055 | 1055 | /// # Examples |
| 1056 | 1056 | /// |
library/core/src/char/methods.rs+2-2| ... | ... | @@ -2354,8 +2354,8 @@ impl char { |
| 2354 | 2354 | /// before using this function. |
| 2355 | 2355 | /// |
| 2356 | 2356 | /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace |
| 2357 | /// [pct]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 | |
| 2358 | /// [bfs]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 | |
| 2357 | /// [pct]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap07.html#tag_07_03_01 | |
| 2358 | /// [bfs]: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_06_05 | |
| 2359 | 2359 | /// |
| 2360 | 2360 | /// # Examples |
| 2361 | 2361 | /// |
library/core/src/io/cursor.rs+38-1| ... | ... | @@ -1,3 +1,5 @@ |
| 1 | use crate::io::{self, ErrorKind, SeekFrom}; | |
| 2 | ||
| 1 | 3 | /// A `Cursor` wraps an in-memory buffer and provides it with a |
| 2 | 4 | /// [`Seek`] implementation. |
| 3 | 5 | /// |
| ... | ... | @@ -21,7 +23,7 @@ |
| 21 | 23 | /// [`File`]: ../../std/fs/struct.File.html |
| 22 | 24 | /// [`Read`]: ../../std/io/trait.Read.html |
| 23 | 25 | /// [`Write`]: ../../std/io/trait.Write.html |
| 24 | /// [`Seek`]: ../../std/io/trait.Seek.html | |
| 26 | /// [`Seek`]: crate::io::Seek | |
| 25 | 27 | /// [Vec]: ../../alloc/vec/struct.Vec.html |
| 26 | 28 | /// |
| 27 | 29 | /// ```no_run |
| ... | ... | @@ -291,3 +293,38 @@ where |
| 291 | 293 | self.pos = other.pos; |
| 292 | 294 | } |
| 293 | 295 | } |
| 296 | ||
| 297 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 298 | impl<T> io::Seek for Cursor<T> | |
| 299 | where | |
| 300 | T: AsRef<[u8]>, | |
| 301 | { | |
| 302 | fn seek(&mut self, style: SeekFrom) -> io::Result<u64> { | |
| 303 | let (base_pos, offset) = match style { | |
| 304 | SeekFrom::Start(n) => { | |
| 305 | self.set_position(n); | |
| 306 | return Ok(n); | |
| 307 | } | |
| 308 | SeekFrom::End(n) => (self.get_ref().as_ref().len() as u64, n), | |
| 309 | SeekFrom::Current(n) => (self.position(), n), | |
| 310 | }; | |
| 311 | match base_pos.checked_add_signed(offset) { | |
| 312 | Some(n) => { | |
| 313 | self.set_position(n); | |
| 314 | Ok(n) | |
| 315 | } | |
| 316 | None => Err(io::const_error!( | |
| 317 | ErrorKind::InvalidInput, | |
| 318 | "invalid seek to a negative or overflowing position", | |
| 319 | )), | |
| 320 | } | |
| 321 | } | |
| 322 | ||
| 323 | fn stream_len(&mut self) -> io::Result<u64> { | |
| 324 | Ok(self.get_ref().as_ref().len() as u64) | |
| 325 | } | |
| 326 | ||
| 327 | fn stream_position(&mut self) -> io::Result<u64> { | |
| 328 | Ok(self.position()) | |
| 329 | } | |
| 330 | } |
library/core/src/io/error.rs+1-1| ... | ... | @@ -80,7 +80,7 @@ pub type Result<T> = result::Result<T, Error>; |
| 80 | 80 | // FIXME(#74481): Hard-links required to link from `core` to `std` |
| 81 | 81 | /// [Read]: ../../std/io/trait.Read.html |
| 82 | 82 | /// [Write]: ../../std/io/trait.Write.html |
| 83 | /// [Seek]: ../../std/io/trait.Seek.html | |
| 83 | /// [Seek]: crate::io::Seek | |
| 84 | 84 | #[stable(feature = "rust1", since = "1.0.0")] |
| 85 | 85 | #[rustc_has_incoherent_inherent_impls] |
| 86 | 86 | pub struct Error { |
library/core/src/io/impls.rs+29-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | use crate::io::SizeHint; | |
| 1 | use crate::io::{self, Seek, SeekFrom, SizeHint}; | |
| 2 | 2 | |
| 3 | 3 | // ============================================================================= |
| 4 | 4 | // Forwarding implementations |
| ... | ... | @@ -17,6 +17,34 @@ impl<T> SizeHint for &mut T { |
| 17 | 17 | } |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 21 | impl<S: Seek + ?Sized> Seek for &mut S { | |
| 22 | #[inline] | |
| 23 | fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { | |
| 24 | (**self).seek(pos) | |
| 25 | } | |
| 26 | ||
| 27 | #[inline] | |
| 28 | fn rewind(&mut self) -> io::Result<()> { | |
| 29 | (**self).rewind() | |
| 30 | } | |
| 31 | ||
| 32 | #[inline] | |
| 33 | fn stream_len(&mut self) -> io::Result<u64> { | |
| 34 | (**self).stream_len() | |
| 35 | } | |
| 36 | ||
| 37 | #[inline] | |
| 38 | fn stream_position(&mut self) -> io::Result<u64> { | |
| 39 | (**self).stream_position() | |
| 40 | } | |
| 41 | ||
| 42 | #[inline] | |
| 43 | fn seek_relative(&mut self, offset: i64) -> io::Result<()> { | |
| 44 | (**self).seek_relative(offset) | |
| 45 | } | |
| 46 | } | |
| 47 | ||
| 20 | 48 | // ============================================================================= |
| 21 | 49 | // In-memory buffer implementations |
| 22 | 50 |
library/core/src/io/mod.rs+4-1| ... | ... | @@ -5,6 +5,7 @@ mod cursor; |
| 5 | 5 | mod error; |
| 6 | 6 | mod impls; |
| 7 | 7 | mod io_slice; |
| 8 | mod seek; | |
| 8 | 9 | mod size_hint; |
| 9 | 10 | mod util; |
| 10 | 11 | |
| ... | ... | @@ -21,12 +22,14 @@ pub use self::{ |
| 21 | 22 | cursor::Cursor, |
| 22 | 23 | error::{Error, ErrorKind, Result}, |
| 23 | 24 | io_slice::{IoSlice, IoSliceMut}, |
| 25 | seek::{Seek, SeekFrom}, | |
| 24 | 26 | util::{Chain, Empty, Repeat, Sink, Take, empty, repeat, sink}, |
| 25 | 27 | }; |
| 26 | 28 | #[doc(hidden)] |
| 27 | 29 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] |
| 28 | 30 | pub use self::{ |
| 29 | 31 | error::{Custom, CustomOwner, OsFunctions}, |
| 32 | seek::stream_len_default, | |
| 30 | 33 | size_hint::SizeHint, |
| 31 | 34 | util::{chain, take}, |
| 32 | 35 | }; |
| ... | ... | @@ -46,7 +49,7 @@ pub use self::{ |
| 46 | 49 | /// [file]: ../../std/fs/struct.File.html |
| 47 | 50 | /// [arc]: ../../alloc/sync/struct.Arc.html |
| 48 | 51 | /// [`Write`]: ../../std/io/trait.Write.html |
| 49 | /// [`Seek`]: ../../std/io/trait.Seek.html | |
| 52 | /// [`Seek`]: crate::io::Seek | |
| 50 | 53 | #[doc(hidden)] |
| 51 | 54 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] |
| 52 | 55 | pub trait IoHandle {} |
library/core/src/io/seek.rs created+221| ... | ... | @@ -0,0 +1,221 @@ |
| 1 | use crate::io::Result; | |
| 2 | ||
| 3 | /// The `Seek` trait provides a cursor which can be moved within a stream of | |
| 4 | /// bytes. | |
| 5 | /// | |
| 6 | /// The stream typically has a fixed size, allowing seeking relative to either | |
| 7 | /// end or the current offset. | |
| 8 | /// | |
| 9 | /// # Examples | |
| 10 | /// | |
| 11 | /// `File`s implement `Seek`: | |
| 12 | /// | |
| 13 | /// ```no_run | |
| 14 | /// use std::io; | |
| 15 | /// use std::io::prelude::*; | |
| 16 | /// use std::fs::File; | |
| 17 | /// use std::io::SeekFrom; | |
| 18 | /// | |
| 19 | /// fn main() -> io::Result<()> { | |
| 20 | /// let mut f = File::open("foo.txt")?; | |
| 21 | /// | |
| 22 | /// // move the cursor 42 bytes from the start of the file | |
| 23 | /// f.seek(SeekFrom::Start(42))?; | |
| 24 | /// Ok(()) | |
| 25 | /// } | |
| 26 | /// ``` | |
| 27 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 28 | #[cfg_attr(not(test), rustc_diagnostic_item = "IoSeek")] | |
| 29 | pub trait Seek { | |
| 30 | /// Seek to an offset, in bytes, in a stream. | |
| 31 | /// | |
| 32 | /// A seek beyond the end of a stream is allowed, but behavior is defined | |
| 33 | /// by the implementation. | |
| 34 | /// | |
| 35 | /// If the seek operation completed successfully, | |
| 36 | /// this method returns the new position from the start of the stream. | |
| 37 | /// That position can be used later with [`SeekFrom::Start`]. | |
| 38 | /// | |
| 39 | /// # Errors | |
| 40 | /// | |
| 41 | /// Seeking can fail, for example because it might involve flushing a buffer. | |
| 42 | /// | |
| 43 | /// Seeking to a negative offset is considered an error. | |
| 44 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 45 | fn seek(&mut self, pos: SeekFrom) -> Result<u64>; | |
| 46 | ||
| 47 | /// Rewind to the beginning of a stream. | |
| 48 | /// | |
| 49 | /// This is a convenience method, equivalent to `seek(SeekFrom::Start(0))`. | |
| 50 | /// | |
| 51 | /// # Errors | |
| 52 | /// | |
| 53 | /// Rewinding can fail, for example because it might involve flushing a buffer. | |
| 54 | /// | |
| 55 | /// # Example | |
| 56 | /// | |
| 57 | /// ```no_run | |
| 58 | /// use std::io::{Read, Seek, Write}; | |
| 59 | /// use std::fs::OpenOptions; | |
| 60 | /// | |
| 61 | /// let mut f = OpenOptions::new() | |
| 62 | /// .write(true) | |
| 63 | /// .read(true) | |
| 64 | /// .create(true) | |
| 65 | /// .open("foo.txt")?; | |
| 66 | /// | |
| 67 | /// let hello = "Hello!\n"; | |
| 68 | /// write!(f, "{hello}")?; | |
| 69 | /// f.rewind()?; | |
| 70 | /// | |
| 71 | /// let mut buf = String::new(); | |
| 72 | /// f.read_to_string(&mut buf)?; | |
| 73 | /// assert_eq!(&buf, hello); | |
| 74 | /// # std::io::Result::Ok(()) | |
| 75 | /// ``` | |
| 76 | #[stable(feature = "seek_rewind", since = "1.55.0")] | |
| 77 | fn rewind(&mut self) -> Result<()> { | |
| 78 | self.seek(SeekFrom::Start(0))?; | |
| 79 | Ok(()) | |
| 80 | } | |
| 81 | ||
| 82 | /// Returns the length of this stream (in bytes). | |
| 83 | /// | |
| 84 | /// The default implementation uses up to three seek operations. If this | |
| 85 | /// method returns successfully, the seek position is unchanged (i.e. the | |
| 86 | /// position before calling this method is the same as afterwards). | |
| 87 | /// However, if this method returns an error, the seek position is | |
| 88 | /// unspecified. | |
| 89 | /// | |
| 90 | /// If you need to obtain the length of *many* streams and you don't care | |
| 91 | /// about the seek position afterwards, you can reduce the number of seek | |
| 92 | /// operations by simply calling `seek(SeekFrom::End(0))` and using its | |
| 93 | /// return value (it is also the stream length). | |
| 94 | /// | |
| 95 | /// Note that length of a stream can change over time (for example, when | |
| 96 | /// data is appended to a file). So calling this method multiple times does | |
| 97 | /// not necessarily return the same length each time. | |
| 98 | /// | |
| 99 | /// # Example | |
| 100 | /// | |
| 101 | /// ```no_run | |
| 102 | /// #![feature(seek_stream_len)] | |
| 103 | /// use std::{ | |
| 104 | /// io::{self, Seek}, | |
| 105 | /// fs::File, | |
| 106 | /// }; | |
| 107 | /// | |
| 108 | /// fn main() -> io::Result<()> { | |
| 109 | /// let mut f = File::open("foo.txt")?; | |
| 110 | /// | |
| 111 | /// let len = f.stream_len()?; | |
| 112 | /// println!("The file is currently {len} bytes long"); | |
| 113 | /// Ok(()) | |
| 114 | /// } | |
| 115 | /// ``` | |
| 116 | #[unstable(feature = "seek_stream_len", issue = "59359")] | |
| 117 | fn stream_len(&mut self) -> Result<u64> { | |
| 118 | stream_len_default(self) | |
| 119 | } | |
| 120 | ||
| 121 | /// Returns the current seek position from the start of the stream. | |
| 122 | /// | |
| 123 | /// This is equivalent to `self.seek(SeekFrom::Current(0))`. | |
| 124 | /// | |
| 125 | /// # Example | |
| 126 | /// | |
| 127 | /// ```no_run | |
| 128 | /// use std::{ | |
| 129 | /// io::{self, BufRead, BufReader, Seek}, | |
| 130 | /// fs::File, | |
| 131 | /// }; | |
| 132 | /// | |
| 133 | /// fn main() -> io::Result<()> { | |
| 134 | /// let mut f = BufReader::new(File::open("foo.txt")?); | |
| 135 | /// | |
| 136 | /// let before = f.stream_position()?; | |
| 137 | /// f.read_line(&mut String::new())?; | |
| 138 | /// let after = f.stream_position()?; | |
| 139 | /// | |
| 140 | /// println!("The first line was {} bytes long", after - before); | |
| 141 | /// Ok(()) | |
| 142 | /// } | |
| 143 | /// ``` | |
| 144 | #[stable(feature = "seek_convenience", since = "1.51.0")] | |
| 145 | fn stream_position(&mut self) -> Result<u64> { | |
| 146 | self.seek(SeekFrom::Current(0)) | |
| 147 | } | |
| 148 | ||
| 149 | /// Seeks relative to the current position. | |
| 150 | /// | |
| 151 | /// This is equivalent to `self.seek(SeekFrom::Current(offset))` but | |
| 152 | /// doesn't return the new position which can allow some implementations | |
| 153 | /// such as `BufReader` to perform more efficient seeks. | |
| 154 | /// | |
| 155 | /// # Example | |
| 156 | /// | |
| 157 | /// ```no_run | |
| 158 | /// use std::{ | |
| 159 | /// io::{self, Seek}, | |
| 160 | /// fs::File, | |
| 161 | /// }; | |
| 162 | /// | |
| 163 | /// fn main() -> io::Result<()> { | |
| 164 | /// let mut f = File::open("foo.txt")?; | |
| 165 | /// f.seek_relative(10)?; | |
| 166 | /// assert_eq!(f.stream_position()?, 10); | |
| 167 | /// Ok(()) | |
| 168 | /// } | |
| 169 | /// ``` | |
| 170 | #[stable(feature = "seek_seek_relative", since = "1.80.0")] | |
| 171 | fn seek_relative(&mut self, offset: i64) -> Result<()> { | |
| 172 | self.seek(SeekFrom::Current(offset))?; | |
| 173 | Ok(()) | |
| 174 | } | |
| 175 | } | |
| 176 | ||
| 177 | /// The default implementation of [`Seek::stream_len`]. | |
| 178 | /// This may be desirable in `libstd` where the default implementation is desirable, | |
| 179 | /// but additional work needs to be done before or after. | |
| 180 | #[doc(hidden)] | |
| 181 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 182 | pub fn stream_len_default<T: Seek + ?Sized>(self_: &mut T) -> Result<u64> { | |
| 183 | let old_pos = self_.stream_position()?; | |
| 184 | let len = self_.seek(SeekFrom::End(0))?; | |
| 185 | ||
| 186 | // Avoid seeking a third time when we were already at the end of the | |
| 187 | // stream. The branch is usually way cheaper than a seek operation. | |
| 188 | if old_pos != len { | |
| 189 | self_.seek(SeekFrom::Start(old_pos))?; | |
| 190 | } | |
| 191 | ||
| 192 | Ok(len) | |
| 193 | } | |
| 194 | ||
| 195 | /// Enumeration of possible methods to seek within an I/O object. | |
| 196 | /// | |
| 197 | /// It is used by the [`Seek`] trait. | |
| 198 | #[derive(Copy, PartialEq, Eq, Clone, Debug)] | |
| 199 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 200 | #[cfg_attr(not(test), rustc_diagnostic_item = "SeekFrom")] | |
| 201 | pub enum SeekFrom { | |
| 202 | /// Sets the offset to the provided number of bytes. | |
| 203 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 204 | Start(#[stable(feature = "rust1", since = "1.0.0")] u64), | |
| 205 | ||
| 206 | /// Sets the offset to the size of this object plus the specified number of | |
| 207 | /// bytes. | |
| 208 | /// | |
| 209 | /// It is possible to seek beyond the end of an object, but it's an error to | |
| 210 | /// seek before byte 0. | |
| 211 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 212 | End(#[stable(feature = "rust1", since = "1.0.0")] i64), | |
| 213 | ||
| 214 | /// Sets the offset to the current position plus the specified number of | |
| 215 | /// bytes. | |
| 216 | /// | |
| 217 | /// It is possible to seek beyond the end of an object, but it's an error to | |
| 218 | /// seek before byte 0. | |
| 219 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 220 | Current(#[stable(feature = "rust1", since = "1.0.0")] i64), | |
| 221 | } |
library/core/src/io/util.rs+62-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | use crate::io::SizeHint; | |
| 1 | use crate::io::{ErrorKind, Result, Seek, SeekFrom, SizeHint}; | |
| 2 | 2 | use crate::{cmp, fmt}; |
| 3 | 3 | |
| 4 | 4 | /// `Empty` ignores any data written via [`Write`], and will always be empty |
| ... | ... | @@ -23,6 +23,24 @@ impl SizeHint for Empty { |
| 23 | 23 | } |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | #[stable(feature = "empty_seek", since = "1.51.0")] | |
| 27 | impl Seek for Empty { | |
| 28 | #[inline] | |
| 29 | fn seek(&mut self, _pos: SeekFrom) -> Result<u64> { | |
| 30 | Ok(0) | |
| 31 | } | |
| 32 | ||
| 33 | #[inline] | |
| 34 | fn stream_len(&mut self) -> Result<u64> { | |
| 35 | Ok(0) | |
| 36 | } | |
| 37 | ||
| 38 | #[inline] | |
| 39 | fn stream_position(&mut self) -> Result<u64> { | |
| 40 | Ok(0) | |
| 41 | } | |
| 42 | } | |
| 43 | ||
| 26 | 44 | /// Creates a value that is always at EOF for reads, and ignores all data written. |
| 27 | 45 | /// |
| 28 | 46 | /// All calls to [`write`] on the returned instance will return [`Ok(buf.len())`] |
| ... | ... | @@ -464,6 +482,49 @@ impl<T> Take<T> { |
| 464 | 482 | } |
| 465 | 483 | } |
| 466 | 484 | |
| 485 | #[stable(feature = "seek_io_take", since = "1.89.0")] | |
| 486 | impl<T: Seek> Seek for Take<T> { | |
| 487 | fn seek(&mut self, pos: SeekFrom) -> Result<u64> { | |
| 488 | let new_position = match pos { | |
| 489 | SeekFrom::Start(v) => Some(v), | |
| 490 | SeekFrom::Current(v) => self.position().checked_add_signed(v), | |
| 491 | SeekFrom::End(v) => self.len.checked_add_signed(v), | |
| 492 | }; | |
| 493 | let new_position = match new_position { | |
| 494 | Some(v) if v <= self.len => v, | |
| 495 | _ => return Err(ErrorKind::InvalidInput.into()), | |
| 496 | }; | |
| 497 | while new_position != self.position() { | |
| 498 | if let Some(offset) = new_position.checked_signed_diff(self.position()) { | |
| 499 | self.inner.seek_relative(offset)?; | |
| 500 | self.limit = self.limit.wrapping_sub(offset as u64); | |
| 501 | break; | |
| 502 | } | |
| 503 | let offset = if new_position > self.position() { i64::MAX } else { i64::MIN }; | |
| 504 | self.inner.seek_relative(offset)?; | |
| 505 | self.limit = self.limit.wrapping_sub(offset as u64); | |
| 506 | } | |
| 507 | Ok(new_position) | |
| 508 | } | |
| 509 | ||
| 510 | fn stream_len(&mut self) -> Result<u64> { | |
| 511 | Ok(self.len) | |
| 512 | } | |
| 513 | ||
| 514 | fn stream_position(&mut self) -> Result<u64> { | |
| 515 | Ok(self.position()) | |
| 516 | } | |
| 517 | ||
| 518 | fn seek_relative(&mut self, offset: i64) -> Result<()> { | |
| 519 | if !self.position().checked_add_signed(offset).is_some_and(|p| p <= self.len) { | |
| 520 | return Err(ErrorKind::InvalidInput.into()); | |
| 521 | } | |
| 522 | self.inner.seek_relative(offset)?; | |
| 523 | self.limit = self.limit.wrapping_sub(offset as u64); | |
| 524 | Ok(()) | |
| 525 | } | |
| 526 | } | |
| 527 | ||
| 467 | 528 | #[doc(hidden)] |
| 468 | 529 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] |
| 469 | 530 | #[must_use] |
library/core/src/num/mod.rs+2-2| ... | ... | @@ -1125,8 +1125,8 @@ impl u8 { |
| 1125 | 1125 | /// before using this function. |
| 1126 | 1126 | /// |
| 1127 | 1127 | /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace |
| 1128 | /// [pct]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 | |
| 1129 | /// [bfs]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 | |
| 1128 | /// [pct]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap07.html#tag_07_03_01 | |
| 1129 | /// [bfs]: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_06_05 | |
| 1130 | 1130 | /// |
| 1131 | 1131 | /// # Examples |
| 1132 | 1132 | /// |
library/core/src/range.rs+13-8| ... | ... | @@ -402,7 +402,8 @@ const impl<T> From<legacy::RangeInclusive<T>> for RangeInclusive<T> { |
| 402 | 402 | /// |
| 403 | 403 | /// # Panics |
| 404 | 404 | /// |
| 405 | /// Panics if the legacy range iterator has been exhausted. | |
| 405 | /// If the legacy range iterator has been exhausted, | |
| 406 | /// this function will either panic or return an empty range. | |
| 406 | 407 | /// |
| 407 | 408 | /// # Examples |
| 408 | 409 | /// |
| ... | ... | @@ -419,19 +420,23 @@ const impl<T> From<legacy::RangeInclusive<T>> for RangeInclusive<T> { |
| 419 | 420 | /// assert_eq!((empty.start, empty.last), (0, 0)); |
| 420 | 421 | /// ``` |
| 421 | 422 | /// |
| 422 | /// ```should_panic | |
| 423 | /// ``` | |
| 424 | /// # // This test requires unwinding to work. | |
| 425 | /// # // Disable it when unwinding isn't available. | |
| 426 | /// # #[cfg(panic = "unwind")] | |
| 427 | /// # fn main() { | |
| 423 | 428 | /// use core::range::legacy; |
| 424 | 429 | /// use core::range::RangeInclusive; |
| 430 | /// use std::panic::catch_unwind; | |
| 425 | 431 | /// |
| 426 | 432 | /// let mut exhausted: legacy::RangeInclusive<i32> = 0..=0; |
| 427 | 433 | /// exhausted.next(); |
| 428 | /// # if exhausted.is_empty() { | |
| 429 | /// # // assert!s don't work correctly in `should_panic` doctests since you | |
| 430 | /// # // can't assert the panic message. Skip the rest of the test instead, | |
| 431 | /// # // so that the expected panic doesn't happen and the test fails. | |
| 432 | /// assert!(exhausted.is_empty()); | |
| 433 | /// let _ = RangeInclusive::from(exhausted); // this panics | |
| 434 | /// let result = catch_unwind(|| RangeInclusive::from(exhausted)); | |
| 435 | /// // The `from` call either panicked or returned an empty range. | |
| 436 | /// assert!(result.is_err() || result.is_ok_and(|range| range.is_empty())); | |
| 434 | 437 | /// # } |
| 438 | /// # #[cfg(not(panic = "unwind"))] | |
| 439 | /// # fn main() {} | |
| 435 | 440 | /// ``` |
| 436 | 441 | #[inline] |
| 437 | 442 | fn from(value: legacy::RangeInclusive<T>) -> Self { |
library/std/src/io/cursor.rs+82-69| ... | ... | @@ -7,42 +7,7 @@ pub use core::io::Cursor; |
| 7 | 7 | use crate::alloc::Allocator; |
| 8 | 8 | use crate::cmp; |
| 9 | 9 | use crate::io::prelude::*; |
| 10 | use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; | |
| 11 | ||
| 12 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 13 | impl<T> io::Seek for Cursor<T> | |
| 14 | where | |
| 15 | T: AsRef<[u8]>, | |
| 16 | { | |
| 17 | fn seek(&mut self, style: SeekFrom) -> io::Result<u64> { | |
| 18 | let (base_pos, offset) = match style { | |
| 19 | SeekFrom::Start(n) => { | |
| 20 | self.set_position(n); | |
| 21 | return Ok(n); | |
| 22 | } | |
| 23 | SeekFrom::End(n) => (self.get_ref().as_ref().len() as u64, n), | |
| 24 | SeekFrom::Current(n) => (self.position(), n), | |
| 25 | }; | |
| 26 | match base_pos.checked_add_signed(offset) { | |
| 27 | Some(n) => { | |
| 28 | self.set_position(n); | |
| 29 | Ok(n) | |
| 30 | } | |
| 31 | None => Err(io::const_error!( | |
| 32 | ErrorKind::InvalidInput, | |
| 33 | "invalid seek to a negative or overflowing position", | |
| 34 | )), | |
| 35 | } | |
| 36 | } | |
| 37 | ||
| 38 | fn stream_len(&mut self) -> io::Result<u64> { | |
| 39 | Ok(self.get_ref().as_ref().len() as u64) | |
| 40 | } | |
| 41 | ||
| 42 | fn stream_position(&mut self) -> io::Result<u64> { | |
| 43 | Ok(self.position()) | |
| 44 | } | |
| 45 | } | |
| 10 | use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; | |
| 46 | 11 | |
| 47 | 12 | #[stable(feature = "rust1", since = "1.0.0")] |
| 48 | 13 | impl<T> Read for Cursor<T> |
| ... | ... | @@ -137,6 +102,54 @@ where |
| 137 | 102 | } |
| 138 | 103 | } |
| 139 | 104 | |
| 105 | /// Trait used to allow indirect implementation of `Write` for `Cursor<Self>`. | |
| 106 | /// Since [`Cursor`] is not a foundational type, it is not possible to implement | |
| 107 | /// `Write` for `Cursor<T>` if `Write` is defined in `libcore` and `T` is in a | |
| 108 | /// downstream crate (e.g., `liballoc` or `libstd`). | |
| 109 | /// | |
| 110 | /// Methods are identical in purpose and meaning to their `Write` namesakes. | |
| 111 | trait WriteThroughCursor: Sized { | |
| 112 | fn write(this: &mut Cursor<Self>, buf: &[u8]) -> io::Result<usize>; | |
| 113 | fn write_vectored(this: &mut Cursor<Self>, bufs: &[IoSlice<'_>]) -> io::Result<usize>; | |
| 114 | fn is_write_vectored(this: &Cursor<Self>) -> bool; | |
| 115 | fn write_all(this: &mut Cursor<Self>, buf: &[u8]) -> io::Result<()>; | |
| 116 | fn write_all_vectored(this: &mut Cursor<Self>, bufs: &mut [IoSlice<'_>]) -> io::Result<()>; | |
| 117 | fn flush(this: &mut Cursor<Self>) -> io::Result<()>; | |
| 118 | } | |
| 119 | ||
| 120 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 121 | impl<W: WriteThroughCursor> Write for Cursor<W> { | |
| 122 | #[inline] | |
| 123 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
| 124 | WriteThroughCursor::write(self, buf) | |
| 125 | } | |
| 126 | ||
| 127 | #[inline] | |
| 128 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
| 129 | WriteThroughCursor::write_vectored(self, bufs) | |
| 130 | } | |
| 131 | ||
| 132 | #[inline] | |
| 133 | fn is_write_vectored(&self) -> bool { | |
| 134 | WriteThroughCursor::is_write_vectored(self) | |
| 135 | } | |
| 136 | ||
| 137 | #[inline] | |
| 138 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { | |
| 139 | WriteThroughCursor::write_all(self, buf) | |
| 140 | } | |
| 141 | ||
| 142 | #[inline] | |
| 143 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { | |
| 144 | WriteThroughCursor::write_all_vectored(self, bufs) | |
| 145 | } | |
| 146 | ||
| 147 | #[inline] | |
| 148 | fn flush(&mut self) -> io::Result<()> { | |
| 149 | WriteThroughCursor::flush(self) | |
| 150 | } | |
| 151 | } | |
| 152 | ||
| 140 | 153 | // Non-resizing write implementation |
| 141 | 154 | #[inline] |
| 142 | 155 | fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<usize> { |
| ... | ... | @@ -348,117 +361,117 @@ impl Write for Cursor<&mut [u8]> { |
| 348 | 361 | } |
| 349 | 362 | |
| 350 | 363 | #[stable(feature = "cursor_mut_vec", since = "1.25.0")] |
| 351 | impl<A> Write for Cursor<&mut Vec<u8, A>> | |
| 364 | impl<A> WriteThroughCursor for &mut Vec<u8, A> | |
| 352 | 365 | where |
| 353 | 366 | A: Allocator, |
| 354 | 367 | { |
| 355 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
| 356 | let (pos, inner) = self.into_parts_mut(); | |
| 368 | fn write(this: &mut Cursor<Self>, buf: &[u8]) -> io::Result<usize> { | |
| 369 | let (pos, inner) = this.into_parts_mut(); | |
| 357 | 370 | vec_write_all(pos, inner, buf) |
| 358 | 371 | } |
| 359 | 372 | |
| 360 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
| 361 | let (pos, inner) = self.into_parts_mut(); | |
| 373 | fn write_vectored(this: &mut Cursor<Self>, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
| 374 | let (pos, inner) = this.into_parts_mut(); | |
| 362 | 375 | vec_write_all_vectored(pos, inner, bufs) |
| 363 | 376 | } |
| 364 | 377 | |
| 365 | 378 | #[inline] |
| 366 | fn is_write_vectored(&self) -> bool { | |
| 379 | fn is_write_vectored(_this: &Cursor<Self>) -> bool { | |
| 367 | 380 | true |
| 368 | 381 | } |
| 369 | 382 | |
| 370 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { | |
| 371 | let (pos, inner) = self.into_parts_mut(); | |
| 383 | fn write_all(this: &mut Cursor<Self>, buf: &[u8]) -> io::Result<()> { | |
| 384 | let (pos, inner) = this.into_parts_mut(); | |
| 372 | 385 | vec_write_all(pos, inner, buf)?; |
| 373 | 386 | Ok(()) |
| 374 | 387 | } |
| 375 | 388 | |
| 376 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { | |
| 377 | let (pos, inner) = self.into_parts_mut(); | |
| 389 | fn write_all_vectored(this: &mut Cursor<Self>, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { | |
| 390 | let (pos, inner) = this.into_parts_mut(); | |
| 378 | 391 | vec_write_all_vectored(pos, inner, bufs)?; |
| 379 | 392 | Ok(()) |
| 380 | 393 | } |
| 381 | 394 | |
| 382 | 395 | #[inline] |
| 383 | fn flush(&mut self) -> io::Result<()> { | |
| 396 | fn flush(_this: &mut Cursor<Self>) -> io::Result<()> { | |
| 384 | 397 | Ok(()) |
| 385 | 398 | } |
| 386 | 399 | } |
| 387 | 400 | |
| 388 | 401 | #[stable(feature = "rust1", since = "1.0.0")] |
| 389 | impl<A> Write for Cursor<Vec<u8, A>> | |
| 402 | impl<A> WriteThroughCursor for Vec<u8, A> | |
| 390 | 403 | where |
| 391 | 404 | A: Allocator, |
| 392 | 405 | { |
| 393 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
| 394 | let (pos, inner) = self.into_parts_mut(); | |
| 406 | fn write(this: &mut Cursor<Self>, buf: &[u8]) -> io::Result<usize> { | |
| 407 | let (pos, inner) = this.into_parts_mut(); | |
| 395 | 408 | vec_write_all(pos, inner, buf) |
| 396 | 409 | } |
| 397 | 410 | |
| 398 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
| 399 | let (pos, inner) = self.into_parts_mut(); | |
| 411 | fn write_vectored(this: &mut Cursor<Self>, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
| 412 | let (pos, inner) = this.into_parts_mut(); | |
| 400 | 413 | vec_write_all_vectored(pos, inner, bufs) |
| 401 | 414 | } |
| 402 | 415 | |
| 403 | 416 | #[inline] |
| 404 | fn is_write_vectored(&self) -> bool { | |
| 417 | fn is_write_vectored(_this: &Cursor<Self>) -> bool { | |
| 405 | 418 | true |
| 406 | 419 | } |
| 407 | 420 | |
| 408 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { | |
| 409 | let (pos, inner) = self.into_parts_mut(); | |
| 421 | fn write_all(this: &mut Cursor<Self>, buf: &[u8]) -> io::Result<()> { | |
| 422 | let (pos, inner) = this.into_parts_mut(); | |
| 410 | 423 | vec_write_all(pos, inner, buf)?; |
| 411 | 424 | Ok(()) |
| 412 | 425 | } |
| 413 | 426 | |
| 414 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { | |
| 415 | let (pos, inner) = self.into_parts_mut(); | |
| 427 | fn write_all_vectored(this: &mut Cursor<Self>, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { | |
| 428 | let (pos, inner) = this.into_parts_mut(); | |
| 416 | 429 | vec_write_all_vectored(pos, inner, bufs)?; |
| 417 | 430 | Ok(()) |
| 418 | 431 | } |
| 419 | 432 | |
| 420 | 433 | #[inline] |
| 421 | fn flush(&mut self) -> io::Result<()> { | |
| 434 | fn flush(_this: &mut Cursor<Self>) -> io::Result<()> { | |
| 422 | 435 | Ok(()) |
| 423 | 436 | } |
| 424 | 437 | } |
| 425 | 438 | |
| 426 | 439 | #[stable(feature = "cursor_box_slice", since = "1.5.0")] |
| 427 | impl<A> Write for Cursor<Box<[u8], A>> | |
| 440 | impl<A> WriteThroughCursor for Box<[u8], A> | |
| 428 | 441 | where |
| 429 | 442 | A: Allocator, |
| 430 | 443 | { |
| 431 | 444 | #[inline] |
| 432 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
| 433 | let (pos, inner) = self.into_parts_mut(); | |
| 445 | fn write(this: &mut Cursor<Self>, buf: &[u8]) -> io::Result<usize> { | |
| 446 | let (pos, inner) = this.into_parts_mut(); | |
| 434 | 447 | slice_write(pos, inner, buf) |
| 435 | 448 | } |
| 436 | 449 | |
| 437 | 450 | #[inline] |
| 438 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
| 439 | let (pos, inner) = self.into_parts_mut(); | |
| 451 | fn write_vectored(this: &mut Cursor<Self>, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
| 452 | let (pos, inner) = this.into_parts_mut(); | |
| 440 | 453 | slice_write_vectored(pos, inner, bufs) |
| 441 | 454 | } |
| 442 | 455 | |
| 443 | 456 | #[inline] |
| 444 | fn is_write_vectored(&self) -> bool { | |
| 457 | fn is_write_vectored(_this: &Cursor<Self>) -> bool { | |
| 445 | 458 | true |
| 446 | 459 | } |
| 447 | 460 | |
| 448 | 461 | #[inline] |
| 449 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { | |
| 450 | let (pos, inner) = self.into_parts_mut(); | |
| 462 | fn write_all(this: &mut Cursor<Self>, buf: &[u8]) -> io::Result<()> { | |
| 463 | let (pos, inner) = this.into_parts_mut(); | |
| 451 | 464 | slice_write_all(pos, inner, buf) |
| 452 | 465 | } |
| 453 | 466 | |
| 454 | 467 | #[inline] |
| 455 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { | |
| 456 | let (pos, inner) = self.into_parts_mut(); | |
| 468 | fn write_all_vectored(this: &mut Cursor<Self>, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { | |
| 469 | let (pos, inner) = this.into_parts_mut(); | |
| 457 | 470 | slice_write_all_vectored(pos, inner, bufs) |
| 458 | 471 | } |
| 459 | 472 | |
| 460 | 473 | #[inline] |
| 461 | fn flush(&mut self) -> io::Result<()> { | |
| 474 | fn flush(_this: &mut Cursor<Self>) -> io::Result<()> { | |
| 462 | 475 | Ok(()) |
| 463 | 476 | } |
| 464 | 477 | } |
library/std/src/io/impls.rs+1-86| ... | ... | @@ -3,7 +3,7 @@ mod tests; |
| 3 | 3 | |
| 4 | 4 | use crate::alloc::Allocator; |
| 5 | 5 | use crate::collections::VecDeque; |
| 6 | use crate::io::{self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; | |
| 6 | use crate::io::{self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Write}; | |
| 7 | 7 | use crate::sync::Arc; |
| 8 | 8 | use crate::{cmp, fmt, mem, str}; |
| 9 | 9 | |
| ... | ... | @@ -90,33 +90,6 @@ impl<W: Write + ?Sized> Write for &mut W { |
| 90 | 90 | } |
| 91 | 91 | } |
| 92 | 92 | #[stable(feature = "rust1", since = "1.0.0")] |
| 93 | impl<S: Seek + ?Sized> Seek for &mut S { | |
| 94 | #[inline] | |
| 95 | fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { | |
| 96 | (**self).seek(pos) | |
| 97 | } | |
| 98 | ||
| 99 | #[inline] | |
| 100 | fn rewind(&mut self) -> io::Result<()> { | |
| 101 | (**self).rewind() | |
| 102 | } | |
| 103 | ||
| 104 | #[inline] | |
| 105 | fn stream_len(&mut self) -> io::Result<u64> { | |
| 106 | (**self).stream_len() | |
| 107 | } | |
| 108 | ||
| 109 | #[inline] | |
| 110 | fn stream_position(&mut self) -> io::Result<u64> { | |
| 111 | (**self).stream_position() | |
| 112 | } | |
| 113 | ||
| 114 | #[inline] | |
| 115 | fn seek_relative(&mut self, offset: i64) -> io::Result<()> { | |
| 116 | (**self).seek_relative(offset) | |
| 117 | } | |
| 118 | } | |
| 119 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 120 | 93 | impl<B: BufRead + ?Sized> BufRead for &mut B { |
| 121 | 94 | #[inline] |
| 122 | 95 | fn fill_buf(&mut self) -> io::Result<&[u8]> { |
| ... | ... | @@ -229,33 +202,6 @@ impl<W: Write + ?Sized> Write for Box<W> { |
| 229 | 202 | } |
| 230 | 203 | } |
| 231 | 204 | #[stable(feature = "rust1", since = "1.0.0")] |
| 232 | impl<S: Seek + ?Sized> Seek for Box<S> { | |
| 233 | #[inline] | |
| 234 | fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { | |
| 235 | (**self).seek(pos) | |
| 236 | } | |
| 237 | ||
| 238 | #[inline] | |
| 239 | fn rewind(&mut self) -> io::Result<()> { | |
| 240 | (**self).rewind() | |
| 241 | } | |
| 242 | ||
| 243 | #[inline] | |
| 244 | fn stream_len(&mut self) -> io::Result<u64> { | |
| 245 | (**self).stream_len() | |
| 246 | } | |
| 247 | ||
| 248 | #[inline] | |
| 249 | fn stream_position(&mut self) -> io::Result<u64> { | |
| 250 | (**self).stream_position() | |
| 251 | } | |
| 252 | ||
| 253 | #[inline] | |
| 254 | fn seek_relative(&mut self, offset: i64) -> io::Result<()> { | |
| 255 | (**self).seek_relative(offset) | |
| 256 | } | |
| 257 | } | |
| 258 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 259 | 205 | impl<B: BufRead + ?Sized> BufRead for Box<B> { |
| 260 | 206 | #[inline] |
| 261 | 207 | fn fill_buf(&mut self) -> io::Result<&[u8]> { |
| ... | ... | @@ -804,34 +750,3 @@ where |
| 804 | 750 | (&**self).write_fmt(fmt) |
| 805 | 751 | } |
| 806 | 752 | } |
| 807 | #[stable(feature = "io_traits_arc", since = "1.73.0")] | |
| 808 | impl<S: Seek + ?Sized> Seek for Arc<S> | |
| 809 | where | |
| 810 | for<'a> &'a S: Seek, | |
| 811 | S: crate::io::IoHandle, | |
| 812 | { | |
| 813 | #[inline] | |
| 814 | fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { | |
| 815 | (&**self).seek(pos) | |
| 816 | } | |
| 817 | ||
| 818 | #[inline] | |
| 819 | fn rewind(&mut self) -> io::Result<()> { | |
| 820 | (&**self).rewind() | |
| 821 | } | |
| 822 | ||
| 823 | #[inline] | |
| 824 | fn stream_len(&mut self) -> io::Result<u64> { | |
| 825 | (&**self).stream_len() | |
| 826 | } | |
| 827 | ||
| 828 | #[inline] | |
| 829 | fn stream_position(&mut self) -> io::Result<u64> { | |
| 830 | (&**self).stream_position() | |
| 831 | } | |
| 832 | ||
| 833 | #[inline] | |
| 834 | fn seek_relative(&mut self, offset: i64) -> io::Result<()> { | |
| 835 | (&**self).seek_relative(offset) | |
| 836 | } | |
| 837 | } |
library/std/src/io/mod.rs+2-264| ... | ... | @@ -299,7 +299,6 @@ mod tests; |
| 299 | 299 | |
| 300 | 300 | use core::slice::memchr; |
| 301 | 301 | |
| 302 | pub(crate) use alloc_crate::io::IoHandle; | |
| 303 | 302 | #[unstable(feature = "raw_os_error_ty", issue = "107792")] |
| 304 | 303 | pub use alloc_crate::io::RawOsError; |
| 305 | 304 | #[doc(hidden)] |
| ... | ... | @@ -311,8 +310,9 @@ pub use alloc_crate::io::const_error; |
| 311 | 310 | pub use alloc_crate::io::{BorrowedBuf, BorrowedCursor}; |
| 312 | 311 | #[stable(feature = "rust1", since = "1.0.0")] |
| 313 | 312 | pub use alloc_crate::io::{ |
| 314 | Chain, Empty, Error, ErrorKind, Repeat, Result, Sink, Take, empty, repeat, sink, | |
| 313 | Chain, Empty, Error, ErrorKind, Repeat, Result, Seek, SeekFrom, Sink, Take, empty, repeat, sink, | |
| 315 | 314 | }; |
| 315 | pub(crate) use alloc_crate::io::{IoHandle, stream_len_default}; | |
| 316 | 316 | #[stable(feature = "iovec", since = "1.36.0")] |
| 317 | 317 | pub use alloc_crate::io::{IoSlice, IoSliceMut}; |
| 318 | 318 | use alloc_crate::io::{OsFunctions, SizeHint}; |
| ... | ... | @@ -1762,225 +1762,6 @@ pub trait Write { |
| 1762 | 1762 | } |
| 1763 | 1763 | } |
| 1764 | 1764 | |
| 1765 | /// The `Seek` trait provides a cursor which can be moved within a stream of | |
| 1766 | /// bytes. | |
| 1767 | /// | |
| 1768 | /// The stream typically has a fixed size, allowing seeking relative to either | |
| 1769 | /// end or the current offset. | |
| 1770 | /// | |
| 1771 | /// # Examples | |
| 1772 | /// | |
| 1773 | /// [`File`]s implement `Seek`: | |
| 1774 | /// | |
| 1775 | /// [`File`]: crate::fs::File | |
| 1776 | /// | |
| 1777 | /// ```no_run | |
| 1778 | /// use std::io; | |
| 1779 | /// use std::io::prelude::*; | |
| 1780 | /// use std::fs::File; | |
| 1781 | /// use std::io::SeekFrom; | |
| 1782 | /// | |
| 1783 | /// fn main() -> io::Result<()> { | |
| 1784 | /// let mut f = File::open("foo.txt")?; | |
| 1785 | /// | |
| 1786 | /// // move the cursor 42 bytes from the start of the file | |
| 1787 | /// f.seek(SeekFrom::Start(42))?; | |
| 1788 | /// Ok(()) | |
| 1789 | /// } | |
| 1790 | /// ``` | |
| 1791 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 1792 | #[cfg_attr(not(test), rustc_diagnostic_item = "IoSeek")] | |
| 1793 | pub trait Seek { | |
| 1794 | /// Seek to an offset, in bytes, in a stream. | |
| 1795 | /// | |
| 1796 | /// A seek beyond the end of a stream is allowed, but behavior is defined | |
| 1797 | /// by the implementation. | |
| 1798 | /// | |
| 1799 | /// If the seek operation completed successfully, | |
| 1800 | /// this method returns the new position from the start of the stream. | |
| 1801 | /// That position can be used later with [`SeekFrom::Start`]. | |
| 1802 | /// | |
| 1803 | /// # Errors | |
| 1804 | /// | |
| 1805 | /// Seeking can fail, for example because it might involve flushing a buffer. | |
| 1806 | /// | |
| 1807 | /// Seeking to a negative offset is considered an error. | |
| 1808 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 1809 | fn seek(&mut self, pos: SeekFrom) -> Result<u64>; | |
| 1810 | ||
| 1811 | /// Rewind to the beginning of a stream. | |
| 1812 | /// | |
| 1813 | /// This is a convenience method, equivalent to `seek(SeekFrom::Start(0))`. | |
| 1814 | /// | |
| 1815 | /// # Errors | |
| 1816 | /// | |
| 1817 | /// Rewinding can fail, for example because it might involve flushing a buffer. | |
| 1818 | /// | |
| 1819 | /// # Example | |
| 1820 | /// | |
| 1821 | /// ```no_run | |
| 1822 | /// use std::io::{Read, Seek, Write}; | |
| 1823 | /// use std::fs::OpenOptions; | |
| 1824 | /// | |
| 1825 | /// let mut f = OpenOptions::new() | |
| 1826 | /// .write(true) | |
| 1827 | /// .read(true) | |
| 1828 | /// .create(true) | |
| 1829 | /// .open("foo.txt")?; | |
| 1830 | /// | |
| 1831 | /// let hello = "Hello!\n"; | |
| 1832 | /// write!(f, "{hello}")?; | |
| 1833 | /// f.rewind()?; | |
| 1834 | /// | |
| 1835 | /// let mut buf = String::new(); | |
| 1836 | /// f.read_to_string(&mut buf)?; | |
| 1837 | /// assert_eq!(&buf, hello); | |
| 1838 | /// # std::io::Result::Ok(()) | |
| 1839 | /// ``` | |
| 1840 | #[stable(feature = "seek_rewind", since = "1.55.0")] | |
| 1841 | fn rewind(&mut self) -> Result<()> { | |
| 1842 | self.seek(SeekFrom::Start(0))?; | |
| 1843 | Ok(()) | |
| 1844 | } | |
| 1845 | ||
| 1846 | /// Returns the length of this stream (in bytes). | |
| 1847 | /// | |
| 1848 | /// The default implementation uses up to three seek operations. If this | |
| 1849 | /// method returns successfully, the seek position is unchanged (i.e. the | |
| 1850 | /// position before calling this method is the same as afterwards). | |
| 1851 | /// However, if this method returns an error, the seek position is | |
| 1852 | /// unspecified. | |
| 1853 | /// | |
| 1854 | /// If you need to obtain the length of *many* streams and you don't care | |
| 1855 | /// about the seek position afterwards, you can reduce the number of seek | |
| 1856 | /// operations by simply calling `seek(SeekFrom::End(0))` and using its | |
| 1857 | /// return value (it is also the stream length). | |
| 1858 | /// | |
| 1859 | /// Note that length of a stream can change over time (for example, when | |
| 1860 | /// data is appended to a file). So calling this method multiple times does | |
| 1861 | /// not necessarily return the same length each time. | |
| 1862 | /// | |
| 1863 | /// # Example | |
| 1864 | /// | |
| 1865 | /// ```no_run | |
| 1866 | /// #![feature(seek_stream_len)] | |
| 1867 | /// use std::{ | |
| 1868 | /// io::{self, Seek}, | |
| 1869 | /// fs::File, | |
| 1870 | /// }; | |
| 1871 | /// | |
| 1872 | /// fn main() -> io::Result<()> { | |
| 1873 | /// let mut f = File::open("foo.txt")?; | |
| 1874 | /// | |
| 1875 | /// let len = f.stream_len()?; | |
| 1876 | /// println!("The file is currently {len} bytes long"); | |
| 1877 | /// Ok(()) | |
| 1878 | /// } | |
| 1879 | /// ``` | |
| 1880 | #[unstable(feature = "seek_stream_len", issue = "59359")] | |
| 1881 | fn stream_len(&mut self) -> Result<u64> { | |
| 1882 | stream_len_default(self) | |
| 1883 | } | |
| 1884 | ||
| 1885 | /// Returns the current seek position from the start of the stream. | |
| 1886 | /// | |
| 1887 | /// This is equivalent to `self.seek(SeekFrom::Current(0))`. | |
| 1888 | /// | |
| 1889 | /// # Example | |
| 1890 | /// | |
| 1891 | /// ```no_run | |
| 1892 | /// use std::{ | |
| 1893 | /// io::{self, BufRead, BufReader, Seek}, | |
| 1894 | /// fs::File, | |
| 1895 | /// }; | |
| 1896 | /// | |
| 1897 | /// fn main() -> io::Result<()> { | |
| 1898 | /// let mut f = BufReader::new(File::open("foo.txt")?); | |
| 1899 | /// | |
| 1900 | /// let before = f.stream_position()?; | |
| 1901 | /// f.read_line(&mut String::new())?; | |
| 1902 | /// let after = f.stream_position()?; | |
| 1903 | /// | |
| 1904 | /// println!("The first line was {} bytes long", after - before); | |
| 1905 | /// Ok(()) | |
| 1906 | /// } | |
| 1907 | /// ``` | |
| 1908 | #[stable(feature = "seek_convenience", since = "1.51.0")] | |
| 1909 | fn stream_position(&mut self) -> Result<u64> { | |
| 1910 | self.seek(SeekFrom::Current(0)) | |
| 1911 | } | |
| 1912 | ||
| 1913 | /// Seeks relative to the current position. | |
| 1914 | /// | |
| 1915 | /// This is equivalent to `self.seek(SeekFrom::Current(offset))` but | |
| 1916 | /// doesn't return the new position which can allow some implementations | |
| 1917 | /// such as [`BufReader`] to perform more efficient seeks. | |
| 1918 | /// | |
| 1919 | /// # Example | |
| 1920 | /// | |
| 1921 | /// ```no_run | |
| 1922 | /// use std::{ | |
| 1923 | /// io::{self, Seek}, | |
| 1924 | /// fs::File, | |
| 1925 | /// }; | |
| 1926 | /// | |
| 1927 | /// fn main() -> io::Result<()> { | |
| 1928 | /// let mut f = File::open("foo.txt")?; | |
| 1929 | /// f.seek_relative(10)?; | |
| 1930 | /// assert_eq!(f.stream_position()?, 10); | |
| 1931 | /// Ok(()) | |
| 1932 | /// } | |
| 1933 | /// ``` | |
| 1934 | /// | |
| 1935 | /// [`BufReader`]: crate::io::BufReader | |
| 1936 | #[stable(feature = "seek_seek_relative", since = "1.80.0")] | |
| 1937 | fn seek_relative(&mut self, offset: i64) -> Result<()> { | |
| 1938 | self.seek(SeekFrom::Current(offset))?; | |
| 1939 | Ok(()) | |
| 1940 | } | |
| 1941 | } | |
| 1942 | ||
| 1943 | pub(crate) fn stream_len_default<T: Seek + ?Sized>(self_: &mut T) -> Result<u64> { | |
| 1944 | let old_pos = self_.stream_position()?; | |
| 1945 | let len = self_.seek(SeekFrom::End(0))?; | |
| 1946 | ||
| 1947 | // Avoid seeking a third time when we were already at the end of the | |
| 1948 | // stream. The branch is usually way cheaper than a seek operation. | |
| 1949 | if old_pos != len { | |
| 1950 | self_.seek(SeekFrom::Start(old_pos))?; | |
| 1951 | } | |
| 1952 | ||
| 1953 | Ok(len) | |
| 1954 | } | |
| 1955 | ||
| 1956 | /// Enumeration of possible methods to seek within an I/O object. | |
| 1957 | /// | |
| 1958 | /// It is used by the [`Seek`] trait. | |
| 1959 | #[derive(Copy, PartialEq, Eq, Clone, Debug)] | |
| 1960 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 1961 | #[cfg_attr(not(test), rustc_diagnostic_item = "SeekFrom")] | |
| 1962 | pub enum SeekFrom { | |
| 1963 | /// Sets the offset to the provided number of bytes. | |
| 1964 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 1965 | Start(#[stable(feature = "rust1", since = "1.0.0")] u64), | |
| 1966 | ||
| 1967 | /// Sets the offset to the size of this object plus the specified number of | |
| 1968 | /// bytes. | |
| 1969 | /// | |
| 1970 | /// It is possible to seek beyond the end of an object, but it's an error to | |
| 1971 | /// seek before byte 0. | |
| 1972 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 1973 | End(#[stable(feature = "rust1", since = "1.0.0")] i64), | |
| 1974 | ||
| 1975 | /// Sets the offset to the current position plus the specified number of | |
| 1976 | /// bytes. | |
| 1977 | /// | |
| 1978 | /// It is possible to seek beyond the end of an object, but it's an error to | |
| 1979 | /// seek before byte 0. | |
| 1980 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 1981 | Current(#[stable(feature = "rust1", since = "1.0.0")] i64), | |
| 1982 | } | |
| 1983 | ||
| 1984 | 1765 | fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) -> Result<usize> { |
| 1985 | 1766 | let mut read = 0; |
| 1986 | 1767 | loop { |
| ... | ... | @@ -2632,49 +2413,6 @@ impl<T: BufRead> BufRead for Take<T> { |
| 2632 | 2413 | } |
| 2633 | 2414 | } |
| 2634 | 2415 | |
| 2635 | #[stable(feature = "seek_io_take", since = "1.89.0")] | |
| 2636 | impl<T: Seek> Seek for Take<T> { | |
| 2637 | fn seek(&mut self, pos: SeekFrom) -> Result<u64> { | |
| 2638 | let new_position = match pos { | |
| 2639 | SeekFrom::Start(v) => Some(v), | |
| 2640 | SeekFrom::Current(v) => self.position().checked_add_signed(v), | |
| 2641 | SeekFrom::End(v) => self.len.checked_add_signed(v), | |
| 2642 | }; | |
| 2643 | let new_position = match new_position { | |
| 2644 | Some(v) if v <= self.len => v, | |
| 2645 | _ => return Err(ErrorKind::InvalidInput.into()), | |
| 2646 | }; | |
| 2647 | while new_position != self.position() { | |
| 2648 | if let Some(offset) = new_position.checked_signed_diff(self.position()) { | |
| 2649 | self.inner.seek_relative(offset)?; | |
| 2650 | self.limit = self.limit.wrapping_sub(offset as u64); | |
| 2651 | break; | |
| 2652 | } | |
| 2653 | let offset = if new_position > self.position() { i64::MAX } else { i64::MIN }; | |
| 2654 | self.inner.seek_relative(offset)?; | |
| 2655 | self.limit = self.limit.wrapping_sub(offset as u64); | |
| 2656 | } | |
| 2657 | Ok(new_position) | |
| 2658 | } | |
| 2659 | ||
| 2660 | fn stream_len(&mut self) -> Result<u64> { | |
| 2661 | Ok(self.len) | |
| 2662 | } | |
| 2663 | ||
| 2664 | fn stream_position(&mut self) -> Result<u64> { | |
| 2665 | Ok(self.position()) | |
| 2666 | } | |
| 2667 | ||
| 2668 | fn seek_relative(&mut self, offset: i64) -> Result<()> { | |
| 2669 | if !self.position().checked_add_signed(offset).is_some_and(|p| p <= self.len) { | |
| 2670 | return Err(ErrorKind::InvalidInput.into()); | |
| 2671 | } | |
| 2672 | self.inner.seek_relative(offset)?; | |
| 2673 | self.limit = self.limit.wrapping_sub(offset as u64); | |
| 2674 | Ok(()) | |
| 2675 | } | |
| 2676 | } | |
| 2677 | ||
| 2678 | 2416 | /// An iterator over `u8` values of a reader. |
| 2679 | 2417 | /// |
| 2680 | 2418 | /// This struct is generally created by calling [`bytes`] on a reader. |
library/std/src/io/util.rs+1-20| ... | ... | @@ -5,8 +5,7 @@ mod tests; |
| 5 | 5 | |
| 6 | 6 | use crate::fmt; |
| 7 | 7 | use crate::io::{ |
| 8 | self, BorrowedCursor, BufRead, Empty, IoSlice, IoSliceMut, Read, Repeat, Seek, SeekFrom, Sink, | |
| 9 | Write, | |
| 8 | self, BorrowedCursor, BufRead, Empty, IoSlice, IoSliceMut, Read, Repeat, Sink, Write, | |
| 10 | 9 | }; |
| 11 | 10 | |
| 12 | 11 | #[stable(feature = "rust1", since = "1.0.0")] |
| ... | ... | @@ -84,24 +83,6 @@ impl BufRead for Empty { |
| 84 | 83 | } |
| 85 | 84 | } |
| 86 | 85 | |
| 87 | #[stable(feature = "empty_seek", since = "1.51.0")] | |
| 88 | impl Seek for Empty { | |
| 89 | #[inline] | |
| 90 | fn seek(&mut self, _pos: SeekFrom) -> io::Result<u64> { | |
| 91 | Ok(0) | |
| 92 | } | |
| 93 | ||
| 94 | #[inline] | |
| 95 | fn stream_len(&mut self) -> io::Result<u64> { | |
| 96 | Ok(0) | |
| 97 | } | |
| 98 | ||
| 99 | #[inline] | |
| 100 | fn stream_position(&mut self) -> io::Result<u64> { | |
| 101 | Ok(0) | |
| 102 | } | |
| 103 | } | |
| 104 | ||
| 105 | 86 | #[stable(feature = "empty_write", since = "1.73.0")] |
| 106 | 87 | impl Write for Empty { |
| 107 | 88 | #[inline] |
library/std/src/lib.rs+1| ... | ... | @@ -374,6 +374,7 @@ |
| 374 | 374 | #![feature(random)] |
| 375 | 375 | #![feature(raw_os_error_ty)] |
| 376 | 376 | #![feature(seek_io_take_position)] |
| 377 | #![feature(seek_stream_len)] | |
| 377 | 378 | #![feature(share_trait)] |
| 378 | 379 | #![feature(slice_internals)] |
| 379 | 380 | #![feature(slice_ptr_get)] |
library/std/src/os/fd/owned.rs+1-1| ... | ... | @@ -199,7 +199,7 @@ impl Drop for OwnedFd { |
| 199 | 199 | unsafe { |
| 200 | 200 | // Note that errors are ignored when closing a file descriptor. According to POSIX 2024, |
| 201 | 201 | // we can and indeed should retry `close` on `EINTR` |
| 202 | // (https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/close.html), | |
| 202 | // (https://pubs.opengroup.org/onlinepubs/9799919799/functions/close.html), | |
| 203 | 203 | // but it is not clear yet how well widely-used implementations are conforming with this |
| 204 | 204 | // mandate since older versions of POSIX left the state of the FD after an `EINTR` |
| 205 | 205 | // unspecified. Ignoring errors is "fine" because some of the major Unices (in |
library/std/src/os/unix/process.rs+1-1| ... | ... | @@ -102,7 +102,7 @@ pub impl(self) trait CommandExt { |
| 102 | 102 | /// locations might not appear where intended. |
| 103 | 103 | /// |
| 104 | 104 | /// [POSIX fork() specification]: |
| 105 | /// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html | |
| 105 | /// https://pubs.opengroup.org/onlinepubs/9799919799/functions/fork.html | |
| 106 | 106 | /// [`std::env`]: mod@crate::env |
| 107 | 107 | /// [`Error::new`]: ../../../io/struct.Error.html#method.new |
| 108 | 108 | /// [`Error::other`]: ../../../io/struct.Error.html#method.other |
library/std/src/path.rs+1-1| ... | ... | @@ -4137,7 +4137,7 @@ impl Error for NormalizeError {} |
| 4137 | 4137 | /// Note that this [may change in the future][changes]. |
| 4138 | 4138 | /// |
| 4139 | 4139 | /// [changes]: io#platform-specific-behavior |
| 4140 | /// [posix-semantics]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13 | |
| 4140 | /// [posix-semantics]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap04.html#tag_04_16 | |
| 4141 | 4141 | /// [windows-path]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew |
| 4142 | 4142 | /// [cygwin-path]: https://cygwin.com/cygwin-api/func-cygwin-conv-path.html |
| 4143 | 4143 | #[stable(feature = "absolute_path", since = "1.79.0")] |
library/std/src/sys/fs/unix.rs+1-1| ... | ... | @@ -1926,7 +1926,7 @@ impl fmt::Debug for File { |
| 1926 | 1926 | // Format in octal, followed by the mode format used in `ls -l`. |
| 1927 | 1927 | // |
| 1928 | 1928 | // References: |
| 1929 | // https://pubs.opengroup.org/onlinepubs/009696899/utilities/ls.html | |
| 1929 | // https://pubs.opengroup.org/onlinepubs/9799919799/utilities/ls.html | |
| 1930 | 1930 | // https://www.gnu.org/software/libc/manual/html_node/Testing-File-Type.html |
| 1931 | 1931 | // https://www.gnu.org/software/libc/manual/html_node/Permission-Bits.html |
| 1932 | 1932 | // |
library/std/src/sys/pal/unix/conf.rs+1-1| ... | ... | @@ -11,7 +11,7 @@ pub fn page_size() -> usize { |
| 11 | 11 | /// `_CS_PATH` or `_CS_V[67]_ENV` in the future). |
| 12 | 12 | /// |
| 13 | 13 | /// [posix_confstr]: |
| 14 | /// https://pubs.opengroup.org/onlinepubs/9699919799/functions/confstr.html | |
| 14 | /// https://pubs.opengroup.org/onlinepubs/9799919799/functions/confstr.html | |
| 15 | 15 | #[cfg(target_vendor = "apple")] |
| 16 | 16 | pub fn confstr( |
| 17 | 17 | key: crate::ffi::c_int, |
library/std/src/sys/pal/unix/sync/mutex.rs+1-1| ... | ... | @@ -25,7 +25,7 @@ impl Mutex { |
| 25 | 25 | // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have |
| 26 | 26 | // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you |
| 27 | 27 | // try to re-lock it from the same thread when you already hold a lock |
| 28 | // (https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html). | |
| 28 | // (https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_mutex_init.html). | |
| 29 | 29 | // This is the case even if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL |
| 30 | 30 | // (https://github.com/rust-lang/rust/issues/33770#issuecomment-220847521) -- in that |
| 31 | 31 | // case, `pthread_mutexattr_settype(PTHREAD_MUTEX_DEFAULT)` will of course be the same |
library/std/src/sys/path/unix.rs+2-2| ... | ... | @@ -20,8 +20,8 @@ pub const HAS_PREFIXES: bool = false; |
| 20 | 20 | pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> { |
| 21 | 21 | // This is mostly a wrapper around collecting `Path::components`, with |
| 22 | 22 | // exceptions made where this conflicts with the POSIX specification. |
| 23 | // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017 | |
| 24 | // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13 | |
| 23 | // See 4.16 Pathname Resolution, IEEE Std 1003.1-2024 | |
| 24 | // https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap04.html#tag_04_16 | |
| 25 | 25 | |
| 26 | 26 | // Get the components, skipping the redundant leading "." component if it exists. |
| 27 | 27 | let mut components = path.strip_prefix(".").unwrap_or(path).components(); |
library/std/src/sys/process/unix/unix.rs+1-1| ... | ... | @@ -1101,7 +1101,7 @@ impl ExitStatus { |
| 1101 | 1101 | pub fn exit_ok(&self) -> Result<(), ExitStatusError> { |
| 1102 | 1102 | // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is |
| 1103 | 1103 | // true on all actual versions of Unix, is widely assumed, and is specified in SuS |
| 1104 | // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not | |
| 1104 | // https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html. If it is not | |
| 1105 | 1105 | // true for a platform pretending to be Unix, the tests (our doctests, and also |
| 1106 | 1106 | // unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too. |
| 1107 | 1107 | match NonZero::try_from(self.0) { |
library/std/src/sys/process/unix/unsupported/wait_status.rs+1-1| ... | ... | @@ -46,7 +46,7 @@ impl ExitStatus { |
| 46 | 46 | pub fn exit_ok(&self) -> Result<(), ExitStatusError> { |
| 47 | 47 | // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is |
| 48 | 48 | // true on all actual versions of Unix, is widely assumed, and is specified in SuS |
| 49 | // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not | |
| 49 | // https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html. If it is not | |
| 50 | 50 | // true for a platform pretending to be Unix, the tests (our doctests, and also |
| 51 | 51 | // unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too. |
| 52 | 52 | match NonZero::try_from(self.wait_status) { |
library/std/src/sys/process/unix/vxworks.rs+1-1| ... | ... | @@ -221,7 +221,7 @@ impl ExitStatus { |
| 221 | 221 | pub fn exit_ok(&self) -> Result<(), ExitStatusError> { |
| 222 | 222 | // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is |
| 223 | 223 | // true on all actual versions of Unix, is widely assumed, and is specified in SuS |
| 224 | // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not | |
| 224 | // https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html. If it is not | |
| 225 | 225 | // true for a platform pretending to be Unix, the tests (our doctests, and also |
| 226 | 226 | // unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too. |
| 227 | 227 | match NonZero::try_from(self.0) { |
src/doc/rustc/src/platform-support/nto-qnx.md+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | **Tier: 3** |
| 4 | 4 | |
| 5 | Support for the [QNX®][qnx.com] [QNX Software Development Platform (SDP)], version 7.0, 7.1 and 8.0. | |
| 5 | Support for the [QNX®](https://qnx.com) [QNX Software Development Platform (SDP)], version 7.0, 7.1 and 8.0. | |
| 6 | 6 | |
| 7 | 7 | [QNX Software Development Platform (SDP)]: https://qnx.software/en/software/products-and-solutions/qnx-software-development-platform |
| 8 | 8 |
src/librustdoc/passes/collect_intra_doc_links.rs+14-5| ... | ... | @@ -31,7 +31,7 @@ use smallvec::{SmallVec, smallvec}; |
| 31 | 31 | use tracing::{debug, info, instrument, trace}; |
| 32 | 32 | |
| 33 | 33 | use crate::clean::utils::find_nearest_parent_module; |
| 34 | use crate::clean::{self, Crate, Item, ItemId, ItemLink, PrimitiveType}; | |
| 34 | use crate::clean::{self, Crate, Item, ItemId, ItemLink, PrimitiveType, reexport_chain}; | |
| 35 | 35 | use crate::core::DocContext; |
| 36 | 36 | use crate::html::markdown::{MarkdownLink, MarkdownLinkRange, markdown_links}; |
| 37 | 37 | use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}; |
| ... | ... | @@ -1148,10 +1148,19 @@ impl LinkCollector<'_, '_> { |
| 1148 | 1148 | // `use` statement, we need to use the `def_id` of the `use` statement, not the |
| 1149 | 1149 | // inlined item. |
| 1150 | 1150 | // <https://github.com/rust-lang/rust/pull/151120> |
| 1151 | let item_id = if let Some(inline_stmt_id) = item.inline_stmt_id | |
| 1152 | && find_attr!(tcx, inline_stmt_id, Deprecated { span, ..} if span == depr_span) | |
| 1153 | { | |
| 1154 | inline_stmt_id.to_def_id() | |
| 1151 | let item_id = if let Some(inline_stmt_id) = item.inline_stmt_id { | |
| 1152 | let target_def_id = item.item_id.expect_def_id(); | |
| 1153 | reexport_chain(tcx, inline_stmt_id, target_def_id) | |
| 1154 | .iter() | |
| 1155 | .flat_map(|reexport| reexport.id()) | |
| 1156 | .find(|&reexport_def_id| { | |
| 1157 | find_attr!( | |
| 1158 | tcx, | |
| 1159 | reexport_def_id, | |
| 1160 | Deprecated { span, .. } if span == depr_span | |
| 1161 | ) | |
| 1162 | }) | |
| 1163 | .unwrap_or(target_def_id) | |
| 1155 | 1164 | } else { |
| 1156 | 1165 | item.item_id.expect_def_id() |
| 1157 | 1166 | }; |
tests/crashes/136661.rs deleted-25| ... | ... | @@ -1,25 +0,0 @@ |
| 1 | //@ known-bug: #136661 | |
| 2 | ||
| 3 | #![allow(unused)] | |
| 4 | ||
| 5 | trait Supertrait<T> {} | |
| 6 | ||
| 7 | trait Other { | |
| 8 | fn method(&self) {} | |
| 9 | } | |
| 10 | ||
| 11 | impl WithAssoc for &'static () { | |
| 12 | type As = (); | |
| 13 | } | |
| 14 | ||
| 15 | trait WithAssoc { | |
| 16 | type As; | |
| 17 | } | |
| 18 | ||
| 19 | trait Trait<P: WithAssoc>: Supertrait<P::As> { | |
| 20 | fn method(&self) {} | |
| 21 | } | |
| 22 | ||
| 23 | fn hrtb<T: for<'a> Trait<&'a ()>>() {} | |
| 24 | ||
| 25 | pub fn main() {} |
tests/rustdoc-ui/intra-doc/deprecated-note-from-inlined-reexport-chain.rs created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | //@ check-pass | |
| 2 | ||
| 3 | // Regression test for https://github.com/rust-lang/rust/issues/158745. | |
| 4 | // This checks that rustdoc resolves intra-doc links in deprecation notes using | |
| 5 | // the re-export that carries the attribute, even when that re-export is later | |
| 6 | // inlined through another re-export. | |
| 7 | ||
| 8 | #![deny(rustdoc::broken_intra_doc_links)] | |
| 9 | ||
| 10 | mod bar { | |
| 11 | pub struct A; | |
| 12 | } | |
| 13 | ||
| 14 | #[deprecated(note = "[std::io::ErrorKind::NotFound]")] | |
| 15 | pub use bar::A; | |
| 16 | ||
| 17 | #[doc(inline)] | |
| 18 | pub use A as X; |
tests/ui-fulldeps/rustc_public/check_transform.rs+1-1| ... | ... | @@ -95,7 +95,7 @@ fn change_panic_msg(mut body: Body, new_msg: &str) -> Body { |
| 95 | 95 | let new_const = MirConst::from_str(new_msg); |
| 96 | 96 | args[0] = Operand::Constant(ConstOperand { |
| 97 | 97 | const_: new_const, |
| 98 | span: bb.terminator.span, | |
| 98 | span: bb.terminator.source_info.span, | |
| 99 | 99 | user_ty: None, |
| 100 | 100 | }); |
| 101 | 101 | } |
tests/ui/check-cfg/target_feature.stderr+7| ... | ... | @@ -14,6 +14,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); |
| 14 | 14 | `7e10` |
| 15 | 15 | `a` |
| 16 | 16 | `aclass` |
| 17 | `acquire-release` | |
| 17 | 18 | `addsubiw` |
| 18 | 19 | `adx` |
| 19 | 20 | `aes` |
| ... | ... | @@ -223,6 +224,8 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); |
| 223 | 224 | `mul32high` |
| 224 | 225 | `multivalue` |
| 225 | 226 | `mutable-globals` |
| 227 | `mve` | |
| 228 | `mve.fp` | |
| 226 | 229 | `neon` |
| 227 | 230 | `nnp-assist` |
| 228 | 231 | `nontrapping-fptoint` |
| ... | ... | @@ -366,6 +369,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); |
| 366 | 369 | `v68` |
| 367 | 370 | `v69` |
| 368 | 371 | `v6k` |
| 372 | `v6m` | |
| 369 | 373 | `v6t2` |
| 370 | 374 | `v7` |
| 371 | 375 | `v71` |
| ... | ... | @@ -374,6 +378,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); |
| 374 | 378 | `v79` |
| 375 | 379 | `v8` |
| 376 | 380 | `v8.1a` |
| 381 | `v8.1m.main` | |
| 377 | 382 | `v8.2a` |
| 378 | 383 | `v8.3a` |
| 379 | 384 | `v8.4a` |
| ... | ... | @@ -382,6 +387,8 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); |
| 382 | 387 | `v8.7a` |
| 383 | 388 | `v8.8a` |
| 384 | 389 | `v8.9a` |
| 390 | `v8m` | |
| 391 | `v8m.main` | |
| 385 | 392 | `v8plus` |
| 386 | 393 | `v9` |
| 387 | 394 | `v9.1a` |
tests/ui/impl-trait/return-never-type.rs created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | //@ edition:2024 | |
| 2 | ||
| 3 | #![feature(never_type)] | |
| 4 | ||
| 5 | use std::ops::Add; | |
| 6 | ||
| 7 | fn foo() -> impl Add<u32> { | |
| 8 | //~^ ERROR cannot add `u32` to `!` | |
| 9 | //~| HELP the trait `Add<u32>` is not implemented for `!` | |
| 10 | unimplemented!() | |
| 11 | //~^ HELP `!` can be coerced to any type; consider casting it to a concrete type that implements the trait | |
| 12 | } | |
| 13 | ||
| 14 | fn main() {} |
tests/ui/impl-trait/return-never-type.stderr created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | error[E0277]: cannot add `u32` to `!` | |
| 2 | --> $DIR/return-never-type.rs:7:13 | |
| 3 | | | |
| 4 | LL | fn foo() -> impl Add<u32> { | |
| 5 | | ^^^^^^^^^^^^^ no implementation for `! + u32` | |
| 6 | ... | |
| 7 | LL | unimplemented!() | |
| 8 | | ---------------- return type was inferred to be `!` here | |
| 9 | | | |
| 10 | = help: the trait `Add<u32>` is not implemented for `!` | |
| 11 | help: `!` can be coerced to any type; consider casting it to a concrete type that implements the trait | |
| 12 | | | |
| 13 | LL | unimplemented!() as /* Type */ | |
| 14 | | +++++++++++++ | |
| 15 | ||
| 16 | error: aborting due to 1 previous error | |
| 17 | ||
| 18 | For more information about this error, try `rustc --explain E0277`. |
tests/ui/impl-trait/unsized_coercion.next.stderr deleted-19| ... | ... | @@ -1,19 +0,0 @@ |
| 1 | error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time | |
| 2 | --> $DIR/unsized_coercion.rs:12:15 | |
| 3 | | | |
| 4 | LL | fn hello() -> Box<impl Trait> { | |
| 5 | | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | |
| 6 | | | |
| 7 | = help: the trait `Sized` is not implemented for `dyn Trait` | |
| 8 | ||
| 9 | error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time | |
| 10 | --> $DIR/unsized_coercion.rs:15:17 | |
| 11 | | | |
| 12 | LL | let x = hello(); | |
| 13 | | ^^^^^^^ doesn't have a size known at compile-time | |
| 14 | | | |
| 15 | = help: the trait `Sized` is not implemented for `dyn Trait` | |
| 16 | ||
| 17 | error: aborting due to 2 previous errors | |
| 18 | ||
| 19 | For more information about this error, try `rustc --explain E0277`. |
tests/ui/impl-trait/unsized_coercion.rs+1-3| ... | ... | @@ -3,17 +3,15 @@ |
| 3 | 3 | |
| 4 | 4 | //@ revisions: next old |
| 5 | 5 | //@[next] compile-flags: -Znext-solver |
| 6 | //@[old] check-pass | |
| 6 | //@ check-pass | |
| 7 | 7 | |
| 8 | 8 | trait Trait {} |
| 9 | 9 | |
| 10 | 10 | impl Trait for u32 {} |
| 11 | 11 | |
| 12 | 12 | fn hello() -> Box<impl Trait> { |
| 13 | //[next]~^ ERROR: the size for values of type `dyn Trait` cannot be known at compilation time | |
| 14 | 13 | if true { |
| 15 | 14 | let x = hello(); |
| 16 | //[next]~^ ERROR: the size for values of type `dyn Trait` cannot be known at compilation time | |
| 17 | 15 | let y: Box<dyn Trait> = x; |
| 18 | 16 | } |
| 19 | 17 | Box::new(1u32) |
tests/ui/parser/bare-type-in-impl-parameter.rs created+1| ... | ... | @@ -0,0 +1 @@ |
| 1 | impl<Y<A, B, C>> Z for X<T> {} //~ ERROR: expected type parameter, found path `Y<A, B, C>` |
tests/ui/parser/bare-type-in-impl-parameter.stderr created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | error: expected type parameter, found path `Y<A, B, C>` | |
| 2 | --> $DIR/bare-type-in-impl-parameter.rs:1:6 | |
| 3 | | | |
| 4 | LL | impl<Y<A, B, C>> Z for X<T> {} | |
| 5 | | ^^^^^^^^^^ | |
| 6 | | | |
| 7 | help: you might have meant to bind a type parameter to a trait | |
| 8 | | | |
| 9 | LL | impl<T: Y<A, B, C>> Z for X<T> {} | |
| 10 | | ++ | |
| 11 | help: alternatively, you might have meant to introduce type parameter | |
| 12 | | | |
| 13 | LL - impl<Y<A, B, C>> Z for X<T> {} | |
| 14 | LL + impl<A, B, C> Z for X<T> {} | |
| 15 | | | |
| 16 | ||
| 17 | error: aborting due to 1 previous error | |
| 18 |
tests/ui/process/process-spawn-failure.rs+1-1| ... | ... | @@ -38,7 +38,7 @@ fn find_zombies() { |
| 38 | 38 | extern crate libc; |
| 39 | 39 | let my_pid = unsafe { libc::getpid() }; |
| 40 | 40 | |
| 41 | // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html | |
| 41 | // https://pubs.opengroup.org/onlinepubs/9799919799/utilities/ps.html | |
| 42 | 42 | let ps_cmd_output = Command::new("ps").args(&["-A", "-o", "pid,ppid,args"]).output().unwrap(); |
| 43 | 43 | let ps_output = String::from_utf8_lossy(&ps_cmd_output.stdout); |
| 44 | 44 | // On AIX, the PPID is not always present, such as when a process is blocked |
tests/ui/sized/infer_var_subtyping.rs created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | // Regression test for failure #4 in <https://github.com/rust-lang/rust/issues/155924>. | |
| 2 | // | |
| 3 | // This checks that when we are checking the sized-ness of an inference variable | |
| 4 | // (here coming from the never-to-any coercion) we consider subtyping. That is, | |
| 5 | // `?0` is sized if `(?0 <: ?1 || ?0 :> ?1) && ?1: Sized`). | |
| 6 | // | |
| 7 | //@ revisions: current next | |
| 8 | //@ ignore-compare-mode-next-solver (explicit revisions) | |
| 9 | //@[next] compile-flags: -Znext-solver | |
| 10 | //@ check-pass | |
| 11 | ||
| 12 | #![feature(never_type)] | |
| 13 | ||
| 14 | fn blah(e: !) { | |
| 15 | let source = Box::new(e); | |
| 16 | let _: Box<dyn Send> = source; | |
| 17 | } | |
| 18 | ||
| 19 | fn main() {} |
tests/ui/specialization/min_specialization/next-solver-region-resolution.rs+1-1| ... | ... | @@ -16,7 +16,7 @@ where |
| 16 | 16 | } |
| 17 | 17 | |
| 18 | 18 | impl<'a, T> Foo for &T |
| 19 | //~^ ERROR: conflicting implementations of trait `Foo` for type `&_` | |
| 19 | //~^ ERROR: cycle detected when computing normalized predicates of `<impl at $DIR/next-solver-region-resolution.rs:18:1: 21:21>` | |
| 20 | 20 | where |
| 21 | 21 | Self::Item: Baz, |
| 22 | 22 | { |
tests/ui/specialization/min_specialization/next-solver-region-resolution.stderr+13-8| ... | ... | @@ -1,17 +1,22 @@ |
| 1 | error[E0119]: conflicting implementations of trait `Foo` for type `&_` | |
| 1 | error[E0391]: cycle detected when computing normalized predicates of `<impl at $DIR/next-solver-region-resolution.rs:18:1: 21:21>` | |
| 2 | 2 | --> $DIR/next-solver-region-resolution.rs:18:1 |
| 3 | 3 | | |
| 4 | LL | / impl<'a, T> Foo for &'a T | |
| 5 | LL | | where | |
| 6 | LL | | Self::Item: 'a, | |
| 7 | | |___________________- first implementation here | |
| 8 | ... | |
| 9 | 4 | LL | / impl<'a, T> Foo for &T |
| 10 | 5 | LL | | |
| 11 | 6 | LL | | where |
| 12 | 7 | LL | | Self::Item: Baz, |
| 13 | | |____________________^ conflicting implementation for `&_` | |
| 8 | | |____________________^ | |
| 9 | | | |
| 10 | = note: ...which immediately requires computing normalized predicates of `<impl at $DIR/next-solver-region-resolution.rs:18:1: 21:21>` again | |
| 11 | note: cycle used when computing whether impls specialize one another | |
| 12 | --> $DIR/next-solver-region-resolution.rs:12:1 | |
| 13 | | | |
| 14 | LL | / impl<'a, T> Foo for &'a T | |
| 15 | LL | | where | |
| 16 | LL | | Self::Item: 'a, | |
| 17 | | |___________________^ | |
| 18 | = note: for more information, see <https://rustc-dev-guide.rust-lang.org/overview.html#queries> and <https://rustc-dev-guide.rust-lang.org/query.html> | |
| 14 | 19 | |
| 15 | 20 | error: aborting due to 1 previous error |
| 16 | 21 | |
| 17 | For more information about this error, try `rustc --explain E0119`. | |
| 22 | For more information about this error, try `rustc --explain E0391`. |
tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr+3-1| ... | ... | @@ -18,8 +18,9 @@ LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {} |
| 18 | 18 | = note: ...which requires building an abstract representation for `accept0::{constant#0}`... |
| 19 | 19 | = note: ...which requires building THIR for `accept0::{constant#0}`... |
| 20 | 20 | = note: ...which requires type-checking `accept0::{constant#0}`... |
| 21 | = note: ...which requires computing normalized predicates of `accept0::{constant#0}`... | |
| 21 | 22 | = note: ...which again requires evaluating type-level constant, completing the cycle |
| 22 | = note: cycle used when checking that `accept0` is well-formed | |
| 23 | = note: cycle used when computing normalized predicates of `accept0` | |
| 23 | 24 | = note: for more information, see <https://rustc-dev-guide.rust-lang.org/overview.html#queries> and <https://rustc-dev-guide.rust-lang.org/query.html> |
| 24 | 25 | |
| 25 | 26 | error[E0391]: cycle detected when checking if `accept1::{constant#0}` is a trivial const |
| ... | ... | @@ -32,6 +33,7 @@ LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {} |
| 32 | 33 | = note: ...which requires building an abstract representation for `accept1::{constant#0}`... |
| 33 | 34 | = note: ...which requires building THIR for `accept1::{constant#0}`... |
| 34 | 35 | = note: ...which requires type-checking `accept1::{constant#0}`... |
| 36 | = note: ...which requires computing normalized predicates of `accept1::{constant#0}`... | |
| 35 | 37 | = note: ...which requires evaluating type-level constant... |
| 36 | 38 | = note: ...which requires const-evaluating + checking `accept1::{constant#0}`... |
| 37 | 39 | = note: ...which again requires checking if `accept1::{constant#0}` is a trivial const, completing the cycle |
tests/ui/traits/next-solver/alias-bound-unsound.rs+1| ... | ... | @@ -21,6 +21,7 @@ trait Foo { |
| 21 | 21 | impl Foo for () { |
| 22 | 22 | type Item = String where String: Copy; |
| 23 | 23 | //~^ ERROR overflow evaluating the requirement `String: Copy` |
| 24 | //~| ERROR: overflow evaluating the requirement `<() as Foo>::Item == _` [E0275] | |
| 24 | 25 | } |
| 25 | 26 | |
| 26 | 27 | fn main() { |
tests/ui/traits/next-solver/alias-bound-unsound.stderr+9-3| ... | ... | @@ -1,3 +1,9 @@ |
| 1 | error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _` | |
| 2 | --> $DIR/alias-bound-unsound.rs:22:5 | |
| 3 | | | |
| 4 | LL | type Item = String where String: Copy; | |
| 5 | | ^^^^^^^^^ | |
| 6 | ||
| 1 | 7 | error[E0275]: overflow evaluating the requirement `String: Copy` |
| 2 | 8 | --> $DIR/alias-bound-unsound.rs:22:38 |
| 3 | 9 | | |
| ... | ... | @@ -13,17 +19,17 @@ LL | type Item: Copy |
| 13 | 19 | | ^^^^ this trait's associated type doesn't have the requirement `String: Copy` |
| 14 | 20 | |
| 15 | 21 | error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == String` |
| 16 | --> $DIR/alias-bound-unsound.rs:28:22 | |
| 22 | --> $DIR/alias-bound-unsound.rs:29:22 | |
| 17 | 23 | | |
| 18 | 24 | LL | let _ = identity(<() as Foo>::copy_me(&x)); |
| 19 | 25 | | ^^^^^^^^^^^^^^^^^^^^^^^^ |
| 20 | 26 | |
| 21 | 27 | error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _` |
| 22 | --> $DIR/alias-bound-unsound.rs:28:43 | |
| 28 | --> $DIR/alias-bound-unsound.rs:29:43 | |
| 23 | 29 | | |
| 24 | 30 | LL | let _ = identity(<() as Foo>::copy_me(&x)); |
| 25 | 31 | | ^^ |
| 26 | 32 | |
| 27 | error: aborting due to 3 previous errors | |
| 33 | error: aborting due to 4 previous errors | |
| 28 | 34 | |
| 29 | 35 | For more information about this error, try `rustc --explain E0275`. |
tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.rs+1| ... | ... | @@ -38,6 +38,7 @@ fn impls_bound<T: Bound>() { |
| 38 | 38 | // - normalize `<Foo as Trait<T>>::Assoc` |
| 39 | 39 | // - via blanket impl, requires where-clause `Foo: Bound` -> cycle |
| 40 | 40 | fn generic<T>() |
| 41 | //~^ ERROR the trait bound `Foo: Bound` is not satisfied | |
| 41 | 42 | where |
| 42 | 43 | <Foo as Trait<T>>::Assoc: Bound, |
| 43 | 44 | //~^ ERROR the trait bound `Foo: Bound` is not satisfied |
tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr+30-3| ... | ... | @@ -1,5 +1,32 @@ |
| 1 | 1 | error[E0277]: the trait bound `Foo: Bound` is not satisfied |
| 2 | --> $DIR/normalizes-to-is-not-productive.rs:42:31 | |
| 2 | --> $DIR/normalizes-to-is-not-productive.rs:40:1 | |
| 3 | | | |
| 4 | LL | / fn generic<T>() | |
| 5 | LL | | | |
| 6 | LL | | where | |
| 7 | LL | | <Foo as Trait<T>>::Assoc: Bound, | |
| 8 | | |____________________________________^ unsatisfied trait bound | |
| 9 | | | |
| 10 | help: the trait `Bound` is not implemented for `Foo` | |
| 11 | --> $DIR/normalizes-to-is-not-productive.rs:18:1 | |
| 12 | | | |
| 13 | LL | struct Foo; | |
| 14 | | ^^^^^^^^^^ | |
| 15 | help: the trait `Bound` is implemented for `u32` | |
| 16 | --> $DIR/normalizes-to-is-not-productive.rs:11:1 | |
| 17 | | | |
| 18 | LL | impl Bound for u32 { | |
| 19 | | ^^^^^^^^^^^^^^^^^^ | |
| 20 | note: required for `Foo` to implement `Trait<T>` | |
| 21 | --> $DIR/normalizes-to-is-not-productive.rs:23:19 | |
| 22 | | | |
| 23 | LL | impl<T: Bound, U> Trait<U> for T { | |
| 24 | | ----- ^^^^^^^^ ^ | |
| 25 | | | | |
| 26 | | unsatisfied trait bound introduced here | |
| 27 | ||
| 28 | error[E0277]: the trait bound `Foo: Bound` is not satisfied | |
| 29 | --> $DIR/normalizes-to-is-not-productive.rs:43:31 | |
| 3 | 30 | | |
| 4 | 31 | LL | <Foo as Trait<T>>::Assoc: Bound, |
| 5 | 32 | | ^^^^^ unsatisfied trait bound |
| ... | ... | @@ -30,7 +57,7 @@ LL | | } |
| 30 | 57 | | |_^ required by this bound in `Bound` |
| 31 | 58 | |
| 32 | 59 | error[E0277]: the trait bound `Foo: Bound` is not satisfied |
| 33 | --> $DIR/normalizes-to-is-not-productive.rs:47:19 | |
| 60 | --> $DIR/normalizes-to-is-not-productive.rs:48:19 | |
| 34 | 61 | | |
| 35 | 62 | LL | impls_bound::<Foo>(); |
| 36 | 63 | | ^^^ unsatisfied trait bound |
| ... | ... | @@ -51,6 +78,6 @@ note: required by a bound in `impls_bound` |
| 51 | 78 | LL | fn impls_bound<T: Bound>() { |
| 52 | 79 | | ^^^^^ required by this bound in `impls_bound` |
| 53 | 80 | |
| 54 | error: aborting due to 2 previous errors | |
| 81 | error: aborting due to 3 previous errors | |
| 55 | 82 | |
| 56 | 83 | For more information about this error, try `rustc --explain E0277`. |
tests/ui/traits/next-solver/find-param-recursion-issue-152716.rs+1-1| ... | ... | @@ -14,7 +14,7 @@ fn foo<T>() |
| 14 | 14 | where |
| 15 | 15 | T: for<'a> Proj<'a, Assoc = for<'b> fn(<T as Proj<'b>>::Assoc)>, |
| 16 | 16 | (): Trait<<T as Proj<'static>>::Assoc> |
| 17 | //~^ ERROR: overflow evaluating the requirement `(): Trait<<T as Proj<'static>>::Assoc>` | |
| 17 | //~^ ERROR: the trait bound `(): Trait<fn(for<'b> fn(<T as Proj<'b>>::Assoc))>` is not satisfied | |
| 18 | 18 | { |
| 19 | 19 | } |
| 20 | 20 |
tests/ui/traits/next-solver/find-param-recursion-issue-152716.stderr+7-4| ... | ... | @@ -1,11 +1,14 @@ |
| 1 | error[E0275]: overflow evaluating the requirement `(): Trait<<T as Proj<'static>>::Assoc>` | |
| 1 | error[E0277]: the trait bound `(): Trait<fn(for<'b> fn(<T as Proj<'b>>::Assoc))>` is not satisfied | |
| 2 | 2 | --> $DIR/find-param-recursion-issue-152716.rs:16:9 |
| 3 | 3 | | |
| 4 | 4 | LL | (): Trait<<T as Proj<'static>>::Assoc> |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<fn(for<'b> fn(<T as Proj<'b>>::Assoc))>` is not implemented for `()` | |
| 6 | 6 | | |
| 7 | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`find_param_recursion_issue_152716`) | |
| 7 | help: consider extending the `where` clause, but there might be an alternative better way to express this requirement | |
| 8 | | | |
| 9 | LL | (): Trait<<T as Proj<'static>>::Assoc>, (): Trait<fn(for<'b> fn(<T as Proj<'b>>::Assoc))> | |
| 10 | | +++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 8 | 11 | |
| 9 | 12 | error: aborting due to 1 previous error |
| 10 | 13 | |
| 11 | For more information about this error, try `rustc --explain E0275`. | |
| 14 | For more information about this error, try `rustc --explain E0277`. |
tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr+11-1| ... | ... | @@ -35,6 +35,16 @@ LL | trait A<T> { |
| 35 | 35 | LL | fn f() |
| 36 | 36 | | ^ this trait's associated function doesn't have the requirement `_: A<T>` |
| 37 | 37 | |
| 38 | error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc == _` | |
| 39 | --> $DIR/normalize-param-env-2.rs:22:5 | |
| 40 | | | |
| 41 | LL | / fn f() | |
| 42 | LL | | where | |
| 43 | LL | | Self::Assoc: A<T>, | |
| 44 | | |__________________________^ | |
| 45 | | | |
| 46 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` | |
| 47 | ||
| 38 | 48 | error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc: A<T>` |
| 39 | 49 | --> $DIR/normalize-param-env-2.rs:24:22 |
| 40 | 50 | | |
| ... | ... | @@ -82,7 +92,7 @@ LL | where |
| 82 | 92 | LL | Self::Assoc: A<T>, |
| 83 | 93 | | ^^^^ required by this bound in `A::f` |
| 84 | 94 | |
| 85 | error: aborting due to 8 previous errors | |
| 95 | error: aborting due to 9 previous errors | |
| 86 | 96 | |
| 87 | 97 | Some errors have detailed explanations: E0275, E0283. |
| 88 | 98 | For more information about an error, try `rustc --explain E0275`. |
tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr+9-1| ... | ... | @@ -1,3 +1,11 @@ |
| 1 | error[E0275]: overflow evaluating the requirement `<T as Trait>::Assoc == _` | |
| 2 | --> $DIR/normalize-param-env-4.rs:17:1 | |
| 3 | | | |
| 4 | LL | / fn foo<T>() | |
| 5 | LL | | where | |
| 6 | LL | | <T as Trait>::Assoc: Trait, | |
| 7 | | |_______________________________^ | |
| 8 | ||
| 1 | 9 | error[E0275]: overflow evaluating the requirement `<T as Trait>::Assoc: Trait` |
| 2 | 10 | --> $DIR/normalize-param-env-4.rs:19:26 |
| 3 | 11 | | |
| ... | ... | @@ -22,6 +30,6 @@ note: required by a bound in `impls_trait` |
| 22 | 30 | LL | fn impls_trait<T: Trait>() {} |
| 23 | 31 | | ^^^^^ required by this bound in `impls_trait` |
| 24 | 32 | |
| 25 | error: aborting due to 3 previous errors | |
| 33 | error: aborting due to 4 previous errors | |
| 26 | 34 | |
| 27 | 35 | For more information about this error, try `rustc --explain E0275`. |
tests/ui/traits/next-solver/normalize/param_env-region-constraints-ambiguity.rs created+101| ... | ... | @@ -0,0 +1,101 @@ |
| 1 | //@ revisions: current next | |
| 2 | //@ ignore-compare-mode-next-solver (explicit revisions) | |
| 3 | //@[next] compile-flags: -Znext-solver | |
| 4 | //@ check-pass | |
| 5 | ||
| 6 | // Regression test for trait-system-refactor-initiative#265. Different where-clauses | |
| 7 | // normalizing to the same bound caused ambiguity errors if we lazily normalized | |
| 8 | // where-clauses when using them to prove a goal. | |
| 9 | // | |
| 10 | // We avoid these errors by eagerly normalizing the `param_env`. | |
| 11 | ||
| 12 | mod one { | |
| 13 | trait Trait { | |
| 14 | type Assoc<'a> | |
| 15 | where | |
| 16 | Self: 'a; | |
| 17 | } | |
| 18 | ||
| 19 | trait Bound<'a> {} | |
| 20 | fn impls_bound<'a, T: Bound<'a>>() {} | |
| 21 | fn foo<'a, T: 'a>() | |
| 22 | where | |
| 23 | T: Trait<Assoc<'a> = T> + Bound<'a>, | |
| 24 | T::Assoc<'a>: Bound<'a>, | |
| 25 | { | |
| 26 | impls_bound::<'_, T>(); | |
| 27 | } | |
| 28 | } | |
| 29 | ||
| 30 | mod two { | |
| 31 | trait Trait { | |
| 32 | type Assoc<'a> | |
| 33 | where | |
| 34 | Self: 'a; | |
| 35 | } | |
| 36 | ||
| 37 | trait Bound {} | |
| 38 | fn impls_bound<T: Bound>() {} | |
| 39 | fn foo<'a, T: 'a>() | |
| 40 | where | |
| 41 | T: Trait<Assoc<'a> = T> + Bound, | |
| 42 | T::Assoc<'a>: Bound, | |
| 43 | { | |
| 44 | impls_bound::<T>(); | |
| 45 | } | |
| 46 | } | |
| 47 | ||
| 48 | // Minimization of tokio-par-util. | |
| 49 | mod three { | |
| 50 | trait Trait1 { | |
| 51 | type Assoc1; | |
| 52 | } | |
| 53 | ||
| 54 | trait Trait2 { | |
| 55 | type Assoc2; | |
| 56 | } | |
| 57 | ||
| 58 | struct Indir<T>(T); | |
| 59 | impl<T> Trait2 for Indir<T> | |
| 60 | where | |
| 61 | T: Trait1, | |
| 62 | T::Assoc1: Trait2 + 'static, | |
| 63 | { | |
| 64 | type Assoc2 = <T::Assoc1 as Trait2>::Assoc2; | |
| 65 | } | |
| 66 | ||
| 67 | struct WrapperTwo<T, U>(T, U); | |
| 68 | ||
| 69 | impl<T, U> Trait1 for WrapperTwo<T, U> | |
| 70 | where | |
| 71 | T: Trait1, | |
| 72 | T::Assoc1: Trait2 + 'static, | |
| 73 | // additional region constraint in this candidate so they | |
| 74 | // can't be merged. | |
| 75 | U: Trait1<Assoc1 = <Indir<T> as Trait2>::Assoc2>, | |
| 76 | U: Trait1<Assoc1 = <T::Assoc1 as Trait2>::Assoc2>, | |
| 77 | { | |
| 78 | type Assoc1 = i32; | |
| 79 | } | |
| 80 | } | |
| 81 | ||
| 82 | // Minimization of `qazer` | |
| 83 | mod four { | |
| 84 | trait Value { | |
| 85 | type SelfType<'a> | |
| 86 | where | |
| 87 | Self: 'a; | |
| 88 | } | |
| 89 | ||
| 90 | trait Repository<T> {} | |
| 91 | struct RedbRepo<From, Into>(From, Into); | |
| 92 | ||
| 93 | impl<From, Into> Repository<Into> for RedbRepo<From, Into> | |
| 94 | where | |
| 95 | for<'a> From: Value<SelfType<'a> = From> + Clone + 'static, | |
| 96 | for<'a> <From as Value>::SelfType<'a>: Clone, | |
| 97 | { | |
| 98 | } | |
| 99 | } | |
| 100 | ||
| 101 | fn main() {} |
tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs+1-2| ... | ... | @@ -13,8 +13,7 @@ fn needs_bar<S: Bar>() {} |
| 13 | 13 | |
| 14 | 14 | fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() { |
| 15 | 15 | needs_bar::<T::Assoc1>(); |
| 16 | //~^ ERROR: the trait bound `<T as Foo2>::Assoc2: Bar` is not satisfied | |
| 17 | //~| ERROR: the size for values of type `<T as Foo2>::Assoc2` cannot be known at compilation time | |
| 16 | //~^ ERROR: the trait bound `<T as Foo1>::Assoc1: Bar` is not satisfied | |
| 18 | 17 | } |
| 19 | 18 | |
| 20 | 19 | fn main() {} |
tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr+4-25| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | error[E0277]: the trait bound `<T as Foo2>::Assoc2: Bar` is not satisfied | |
| 1 | error[E0277]: the trait bound `<T as Foo1>::Assoc1: Bar` is not satisfied | |
| 2 | 2 | --> $DIR/recursive-self-normalization-2.rs:15:17 |
| 3 | 3 | | |
| 4 | 4 | LL | needs_bar::<T::Assoc1>(); |
| 5 | | ^^^^^^^^^ the trait `Bar` is not implemented for `<T as Foo2>::Assoc2` | |
| 5 | | ^^^^^^^^^ the trait `Bar` is not implemented for `<T as Foo1>::Assoc1` | |
| 6 | 6 | | |
| 7 | 7 | note: required by a bound in `needs_bar` |
| 8 | 8 | --> $DIR/recursive-self-normalization-2.rs:12:17 |
| ... | ... | @@ -11,30 +11,9 @@ LL | fn needs_bar<S: Bar>() {} |
| 11 | 11 | | ^^^ required by this bound in `needs_bar` |
| 12 | 12 | help: consider further restricting the associated type |
| 13 | 13 | | |
| 14 | LL | fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() where <T as Foo2>::Assoc2: Bar { | |
| 14 | LL | fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() where <T as Foo1>::Assoc1: Bar { | |
| 15 | 15 | | ++++++++++++++++++++++++++++++ |
| 16 | 16 | |
| 17 | error[E0277]: the size for values of type `<T as Foo2>::Assoc2` cannot be known at compilation time | |
| 18 | --> $DIR/recursive-self-normalization-2.rs:15:17 | |
| 19 | | | |
| 20 | LL | needs_bar::<T::Assoc1>(); | |
| 21 | | ^^^^^^^^^ doesn't have a size known at compile-time | |
| 22 | | | |
| 23 | = help: the trait `Sized` is not implemented for `<T as Foo2>::Assoc2` | |
| 24 | note: required by an implicit `Sized` bound in `needs_bar` | |
| 25 | --> $DIR/recursive-self-normalization-2.rs:12:14 | |
| 26 | | | |
| 27 | LL | fn needs_bar<S: Bar>() {} | |
| 28 | | ^ required by the implicit `Sized` requirement on this type parameter in `needs_bar` | |
| 29 | help: consider further restricting the associated type | |
| 30 | | | |
| 31 | LL | fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() where <T as Foo2>::Assoc2: Sized { | |
| 32 | | ++++++++++++++++++++++++++++++++ | |
| 33 | help: consider relaxing the implicit `Sized` restriction | |
| 34 | | | |
| 35 | LL | fn needs_bar<S: Bar + ?Sized>() {} | |
| 36 | | ++++++++ | |
| 37 | ||
| 38 | error: aborting due to 2 previous errors | |
| 17 | error: aborting due to 1 previous error | |
| 39 | 18 | |
| 40 | 19 | For more information about this error, try `rustc --explain E0277`. |
tests/ui/traits/normalize/normalize-param-env-missing-implied-bound-1.rs created+41| ... | ... | @@ -0,0 +1,41 @@ |
| 1 | //@ check-pass | |
| 2 | //@ revisions: current next | |
| 3 | //@ ignore-compare-mode-next-solver (explicit revisions) | |
| 4 | //@[next] compile-flags: -Znext-solver | |
| 5 | ||
| 6 | // In `fn hrtb` normalizing the elaborated where-clause | |
| 7 | // `T: for<'a> Supertrait<<&'a () as WithAssoc>::As>` results in | |
| 8 | // a region error as `&'a ()` is not equal to `&'static ()`. | |
| 9 | // | |
| 10 | // This happens even though the where-clauses themselves are well-formed | |
| 11 | // as we never have to prove `&'a (): WithAssoc` as `'a` is a bound variable. | |
| 12 | // | |
| 13 | // I don't think this can cause unsoundness and has already been accepted in the | |
| 14 | // old solver as we didn't register TypeOutlives constraints if `ignoring_regions` | |
| 15 | // is set. The new solver always registers outlives constraints, so this then | |
| 16 | // caused an error there. We need to ignore these region errors with the new solver | |
| 17 | // due to trait-system-refactor-initiative#166. | |
| 18 | ||
| 19 | #![allow(unused)] | |
| 20 | ||
| 21 | trait Supertrait<T> {} | |
| 22 | ||
| 23 | trait Other { | |
| 24 | fn method(&self) {} | |
| 25 | } | |
| 26 | ||
| 27 | impl<T: 'static> WithAssoc for T { | |
| 28 | type As = T; | |
| 29 | } | |
| 30 | ||
| 31 | trait WithAssoc { | |
| 32 | type As; | |
| 33 | } | |
| 34 | ||
| 35 | trait Trait<P: WithAssoc>: Supertrait<P::As> { | |
| 36 | fn method(&self) {} | |
| 37 | } | |
| 38 | ||
| 39 | fn hrtb<T: for<'a> Trait<&'a ()>>() {} | |
| 40 | ||
| 41 | pub fn main() {} |
tests/ui/traits/normalize/normalize-param-env-missing-implied-bound-2.rs created+39| ... | ... | @@ -0,0 +1,39 @@ |
| 1 | //@ check-pass | |
| 2 | //@ revisions: current next | |
| 3 | //@ ignore-compare-mode-next-solver (explicit revisions) | |
| 4 | //@[next] compile-flags: -Znext-solver | |
| 5 | ||
| 6 | // In `fn hrtb` normalizing the elaborated where-clause | |
| 7 | // `T: for<'a> Supertrait<<&'a () as WithAssoc>::As>` results in | |
| 8 | // a region error as `&'a ()` is not `'static`. | |
| 9 | // | |
| 10 | // This happens even though the where-clauses themselves are well-formed | |
| 11 | // as we never have to prove `&'a (): WithAssoc` as `'a` is a bound variable. | |
| 12 | // | |
| 13 | // Unlike `normalize-param-env-missing-implied-bound-1.rs` this snippet caused | |
| 14 | // an ICE with the old trait solver, as we did register region constraints from | |
| 15 | // relating types. This ICE was tracked in #136661. | |
| 16 | ||
| 17 | #![allow(unused)] | |
| 18 | ||
| 19 | trait Supertrait<T> {} | |
| 20 | ||
| 21 | trait Other { | |
| 22 | fn method(&self) {} | |
| 23 | } | |
| 24 | ||
| 25 | impl WithAssoc for &'static () { | |
| 26 | type As = (); | |
| 27 | } | |
| 28 | ||
| 29 | trait WithAssoc { | |
| 30 | type As; | |
| 31 | } | |
| 32 | ||
| 33 | trait Trait<P: WithAssoc>: Supertrait<P::As> { | |
| 34 | fn method(&self) {} | |
| 35 | } | |
| 36 | ||
| 37 | fn hrtb<T: for<'a> Trait<&'a ()>>() {} | |
| 38 | ||
| 39 | pub fn main() {} |