diff options
46 files changed, 502 insertions, 276 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index ec4b2e9d3e4..748c8b9e442 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -325,7 +325,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { if errors.is_empty() { definition_ty } else { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); self.tcx.ty_error(reported) } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 656baa784d7..61c4d28bdfa 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -769,7 +769,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors, None); + infcx.err_ctxt().report_fulfillment_errors(&errors); } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index be0ae4ce2ef..14dc9d89180 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -444,7 +444,7 @@ fn check_opaque_meets_bounds<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors, None); + infcx.err_ctxt().report_fulfillment_errors(&errors); } match origin { // Checked when type checking the function containing them. @@ -1545,6 +1545,6 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { let errors = fulfillment_cx.select_all_or_error(&infcx); debug!(?errors); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors, None); + infcx.err_ctxt().report_fulfillment_errors(&errors); } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 5adc7a87323..5e2781925e6 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -320,7 +320,7 @@ fn compare_method_predicate_entailment<'tcx>( }); } CheckImpliedWfMode::Skip => { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); return Err(reported); } } @@ -720,7 +720,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // RPITs. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); return Err(reported); } @@ -1731,7 +1731,7 @@ pub(super) fn compare_impl_const_raw( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None)); + return Err(infcx.err_ctxt().report_fulfillment_errors(&errors)); } let outlives_environment = OutlivesEnvironment::new(param_env); @@ -1831,7 +1831,7 @@ fn compare_type_predicate_entailment<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); return Err(reported); } @@ -2044,7 +2044,7 @@ pub(super) fn check_type_bounds<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); return Err(reported); } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 4cccdf30c5f..71050864ce0 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -111,7 +111,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( let errors = wfcx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors, None); + infcx.err_ctxt().report_fulfillment_errors(&errors); return; } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 8294d92c936..5e8f69677cf 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -345,7 +345,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef }), ); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors, None); + infcx.err_ctxt().report_fulfillment_errors(&errors); } // Finally, resolve all regions. @@ -585,7 +585,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, [source, target]); let errors = traits::fully_solve_obligation(&infcx, predicate); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors, None); + infcx.err_ctxt().report_fulfillment_errors(&errors); } // Finally, resolve all regions. diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index daa5d15704d..58dd03811f7 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -174,7 +174,7 @@ fn get_impl_substs( let errors = ocx.select_all_or_error(); if !errors.is_empty() { - ocx.infcx.err_ctxt().report_fulfillment_errors(&errors, None); + ocx.infcx.err_ctxt().report_fulfillment_errors(&errors); return None; } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 33c132fd534..7abdde2c892 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -176,7 +176,7 @@ fn require_same_types<'tcx>( match &errors[..] { [] => true, errors => { - infcx.err_ctxt().report_fulfillment_errors(errors, None); + infcx.err_ctxt().report_fulfillment_errors(errors); false } } @@ -309,7 +309,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { ocx.register_bound(cause, param_env, norm_return_ty, term_did); let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors, None); + infcx.err_ctxt().report_fulfillment_errors(&errors); error = true; } // now we can take the return type of the given main function diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index ac7d984c161..2075537cad7 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -581,7 +581,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !errors.is_empty() { self.adjust_fulfillment_errors_for_expr_obligation(&mut errors); - self.err_ctxt().report_fulfillment_errors(&errors, self.inh.body_id); + self.err_ctxt().report_fulfillment_errors(&errors); } } @@ -594,7 +594,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !result.is_empty() { mutate_fulfillment_errors(&mut result); self.adjust_fulfillment_errors_for_expr_obligation(&mut result); - self.err_ctxt().report_fulfillment_errors(&result, self.inh.body_id); + self.err_ctxt().report_fulfillment_errors(&result); } } @@ -1411,7 +1411,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { let e = self.tainted_by_errors().unwrap_or_else(|| { self.err_ctxt() - .emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true) + .emit_inference_failure_err(self.body_id, sp, ty.into(), E0282, true) .emit() }); let err = self.tcx.ty_error(e); diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs index 26020382d81..07fa7c55df6 100644 --- a/compiler/rustc_hir_typeck/src/inherited.rs +++ b/compiler/rustc_hir_typeck/src/inherited.rs @@ -58,8 +58,6 @@ pub struct Inherited<'tcx> { pub(super) deferred_generator_interiors: RefCell<Vec<(LocalDefId, hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>, - pub(super) body_id: Option<hir::BodyId>, - /// Whenever we introduce an adjustment from `!` into a type variable, /// we record that type variable here. This is later used to inform /// fallback. See the `fallback` module for details. @@ -80,7 +78,6 @@ impl<'tcx> Deref for Inherited<'tcx> { /// without using `Rc` or something similar. pub struct InheritedBuilder<'tcx> { infcx: infer::InferCtxtBuilder<'tcx>, - def_id: LocalDefId, typeck_results: RefCell<ty::TypeckResults<'tcx>>, } @@ -93,7 +90,6 @@ impl<'tcx> Inherited<'tcx> { .infer_ctxt() .ignoring_regions() .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)), - def_id, typeck_results: RefCell::new(ty::TypeckResults::new(hir_owner)), } } @@ -104,19 +100,13 @@ impl<'tcx> InheritedBuilder<'tcx> { where F: FnOnce(&Inherited<'tcx>) -> R, { - let def_id = self.def_id; - f(&Inherited::new(self.infcx.build(), def_id, self.typeck_results)) + f(&Inherited::new(self.infcx.build(), self.typeck_results)) } } impl<'tcx> Inherited<'tcx> { - fn new( - infcx: InferCtxt<'tcx>, - def_id: LocalDefId, - typeck_results: RefCell<ty::TypeckResults<'tcx>>, - ) -> Self { + fn new(infcx: InferCtxt<'tcx>, typeck_results: RefCell<ty::TypeckResults<'tcx>>) -> Self { let tcx = infcx.tcx; - let body_id = tcx.hir().maybe_body_owned_by(def_id); Inherited { typeck_results, @@ -130,7 +120,6 @@ impl<'tcx> Inherited<'tcx> { deferred_asm_checks: RefCell::new(Vec::new()), deferred_generator_interiors: RefCell::new(Vec::new()), diverging_type_vars: RefCell::new(Default::default()), - body_id, infer_var_info: RefCell::new(Default::default()), } } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 00348f3afdc..af588b16d59 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -748,7 +748,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { .infcx .err_ctxt() .emit_inference_failure_err( - Some(self.body.id()), + self.tcx.hir().body_owner_def_id(self.body.id()), self.span.to_span(self.tcx), p.into(), E0282, diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index a3151d2d365..bde16fad821 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -10,7 +10,7 @@ use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def::{CtorOf, DefKind, Namespace}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource}; use rustc_middle::hir::nested_filter; @@ -386,7 +386,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self, error_code))] pub fn emit_inference_failure_err( &self, - body_id: Option<hir::BodyId>, + body_def_id: LocalDefId, failure_span: Span, arg: GenericArg<'tcx>, error_code: TypeAnnotationNeeded, @@ -403,8 +403,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; let mut local_visitor = FindInferSourceVisitor::new(&self, typeck_results, arg); - if let Some(body_id) = body_id { - let expr = self.tcx.hir().expect_expr(body_id.hir_id); + if let Some(body_id) = self.tcx.hir().maybe_body_owned_by( + self.tcx.typeck_root_def_id(body_def_id.to_def_id()).expect_local(), + ) { + let expr = self.tcx.hir().body(body_id).value; local_visitor.visit_expr(expr); } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 3ca17e7273e..ae0bb4949c7 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -117,7 +117,7 @@ pub fn suggest_arbitrary_trait_bound<'tcx>( } let param_name = trait_pred.skip_binder().self_ty().to_string(); - let mut constraint = trait_pred.print_modifiers_and_trait_path().to_string(); + let mut constraint = trait_pred.to_string(); if let Some((name, term)) = associated_ty { // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err. @@ -144,7 +144,7 @@ pub fn suggest_arbitrary_trait_bound<'tcx>( this requirement", if generics.where_clause_span.is_empty() { "introducing a" } else { "extending the" }, ), - format!("{} {}: {}", generics.add_where_or_trailing_comma(), param_name, constraint), + format!("{} {constraint}", generics.add_where_or_trailing_comma()), Applicability::MaybeIncorrect, ); true diff --git a/compiler/rustc_parse/locales/en-US.ftl b/compiler/rustc_parse/locales/en-US.ftl index e76e91fc1b1..5c7dc1e2abf 100644 --- a/compiler/rustc_parse/locales/en-US.ftl +++ b/compiler/rustc_parse/locales/en-US.ftl @@ -412,8 +412,7 @@ parse_fn_ptr_with_generics = function pointer types may not have generic paramet *[false] a } `for` parameter list -parse_invalid_identifier_with_leading_number = expected identifier, found number literal - .label = identifiers cannot start with a number +parse_invalid_identifier_with_leading_number = identifiers cannot start with a number parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn` .suggestion = replace `fn` with `impl` here diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 1662db36d10..63e5bc50513 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -939,6 +939,7 @@ pub(crate) struct ExpectedIdentifier { pub token: Token, pub suggest_raw: Option<SuggEscapeToUseAsIdentifier>, pub suggest_remove_comma: Option<SuggRemoveComma>, + pub help_cannot_start_number: Option<HelpIdentifierStartsWithNumber>, } impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier { @@ -975,10 +976,18 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier { sugg.add_to_diagnostic(&mut diag); } + if let Some(help) = self.help_cannot_start_number { + help.add_to_diagnostic(&mut diag); + } + diag } } +#[derive(Subdiagnostic)] +#[help(parse_invalid_identifier_with_leading_number)] +pub(crate) struct HelpIdentifierStartsWithNumber; + pub(crate) struct ExpectedSemi { pub span: Span, pub token: Token, @@ -1208,14 +1217,6 @@ pub(crate) struct SelfParamNotFirst { } #[derive(Diagnostic)] -#[diag(parse_invalid_identifier_with_leading_number)] -pub(crate) struct InvalidIdentiferStartsWithNumber { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(parse_const_generic_without_braces)] pub(crate) struct ConstGenericWithoutBraces { #[primary_span] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 0a65c37ea7b..5b12bcc1822 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -8,14 +8,14 @@ use crate::errors::{ ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, - GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, InInTypo, - IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, ParenthesesInForHead, - ParenthesesInForHeadSugg, PatternMethodParamWithoutBody, QuestionMarkInType, - QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, - StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg, - SuggEscapeToUseAsIdentifier, SuggRemoveComma, UnexpectedConstInGenericParam, - UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, - UseEqInstead, + GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, + HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon, + IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg, + PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, + StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, + StructLiteralNeedingParensSugg, SuggEscapeToUseAsIdentifier, SuggRemoveComma, + UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, + UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, }; use crate::fluent_generated as fluent; @@ -280,6 +280,7 @@ impl<'a> Parser<'a> { TokenKind::CloseDelim(Delimiter::Brace), TokenKind::CloseDelim(Delimiter::Parenthesis), ]; + let suggest_raw = match self.token.ident() { Some((ident, false)) if ident.is_raw_guess() @@ -295,18 +296,19 @@ impl<'a> Parser<'a> { _ => None, }; - let suggest_remove_comma = - if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { - Some(SuggRemoveComma { span: self.token.span }) - } else { - None - }; + let suggest_remove_comma = (self.token == token::Comma + && self.look_ahead(1, |t| t.is_ident())) + .then_some(SuggRemoveComma { span: self.token.span }); + + let help_cannot_start_number = + self.is_lit_bad_ident().then_some(HelpIdentifierStartsWithNumber); let err = ExpectedIdentifier { span: self.token.span, token: self.token.clone(), suggest_raw, suggest_remove_comma, + help_cannot_start_number, }; let mut err = err.into_diagnostic(&self.sess.span_diagnostic); @@ -365,6 +367,17 @@ impl<'a> Parser<'a> { err } + /// Checks if the current token is a integer or float literal and looks like + /// it could be a invalid identifier with digits at the start. + pub(super) fn is_lit_bad_ident(&mut self) -> bool { + matches!(self.token.uninterpolate().kind, token::Literal(Lit { kind: token::LitKind::Integer | token::LitKind::Float, .. }) + // ensure that the integer literal is followed by a *invalid* + // suffix: this is how we know that it is a identifier with an + // invalid beginning. + if rustc_ast::MetaItemLit::from_token(&self.token).is_none() + ) + } + pub(super) fn expected_one_of_not_found( &mut self, edible: &[TokenKind], diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 8e920f1c421..fc9f1d1330a 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -348,6 +348,10 @@ impl<'a> Parser<'a> { lo = self.token.span; } + if self.is_lit_bad_ident() { + return Err(self.expected_ident_found()); + } + let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd { self.parse_pat_deref(expected)? } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 92a22ffc2b0..fbe5b88c49e 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -273,7 +273,6 @@ impl<'a> Parser<'a> { self.bump(); } - self.report_invalid_identifier_error()?; let (pat, colon) = self.parse_pat_before_ty(None, RecoverComma::Yes, PatternLocation::LetBinding)?; @@ -366,17 +365,6 @@ impl<'a> Parser<'a> { Ok(P(ast::Local { ty, pat, kind, id: DUMMY_NODE_ID, span: lo.to(hi), attrs, tokens: None })) } - /// report error for `let 1x = 123` - pub fn report_invalid_identifier_error(&mut self) -> PResult<'a, ()> { - if let token::Literal(lit) = self.token.uninterpolate().kind && - rustc_ast::MetaItemLit::from_token(&self.token).is_none() && - (lit.kind == token::LitKind::Integer || lit.kind == token::LitKind::Float) && - self.look_ahead(1, |t| matches!(t.kind, token::Eq) || matches!(t.kind, token::Colon ) ) { - return Err(self.sess.create_err(errors::InvalidIdentiferStartsWithNumber { span: self.token.span })); - } - Ok(()) - } - fn check_let_else_init_bool_expr(&self, init: &ast::Expr) { if let ast::ExprKind::Binary(op, ..) = init.kind { if op.node.lazy() { diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 95612674eb9..ca438a103cf 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -93,37 +93,42 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }; // Guard against `<T as Trait<?0>>::Assoc = ?0>`. - struct ContainsTerm<'tcx> { + struct ContainsTerm<'a, 'tcx> { term: ty::Term<'tcx>, + infcx: &'a InferCtxt<'tcx>, } - impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ContainsTerm<'tcx> { + impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ContainsTerm<'_, 'tcx> { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - if t.needs_infer() { - if ty::Term::from(t) == self.term { - ControlFlow::Break(()) - } else { - t.super_visit_with(self) - } + if let Some(vid) = t.ty_vid() + && let ty::TermKind::Ty(term) = self.term.unpack() + && let Some(term_vid) = term.ty_vid() + && self.infcx.root_var(vid) == self.infcx.root_var(term_vid) + { + ControlFlow::Break(()) + } else if t.has_non_region_infer() { + t.super_visit_with(self) } else { ControlFlow::Continue(()) } } fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - if c.needs_infer() { - if ty::Term::from(c) == self.term { - ControlFlow::Break(()) - } else { - c.super_visit_with(self) - } + if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = c.kind() + && let ty::TermKind::Const(term) = self.term.unpack() + && let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() + && self.infcx.root_const_var(vid) == self.infcx.root_const_var(term_vid) + { + ControlFlow::Break(()) + } else if c.has_non_region_infer() { + c.super_visit_with(self) } else { ControlFlow::Continue(()) } } } - let mut visitor = ContainsTerm { term: goal.predicate.term }; + let mut visitor = ContainsTerm { infcx: self.infcx, term: goal.predicate.term }; term_is_infer && goal.predicate.projection_ty.visit_with(&mut visitor).is_continue() diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index a844a1494e2..2dfebfcb904 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -24,11 +24,9 @@ use rustc_errors::{ }; use rustc_hir as hir; use rustc_hir::def::Namespace; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; -use rustc_hir::GenericParam; -use rustc_hir::Item; -use rustc_hir::Node; +use rustc_hir::{GenericParam, Item, Node}; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::{InferOk, TypeTrace}; use rustc_middle::traits::select::OverflowError; @@ -126,11 +124,7 @@ pub trait TypeErrCtxtExt<'tcx> { + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug; - fn report_fulfillment_errors( - &self, - errors: &[FulfillmentError<'tcx>], - body_id: Option<hir::BodyId>, - ) -> ErrorGuaranteed; + fn report_fulfillment_errors(&self, errors: &[FulfillmentError<'tcx>]) -> ErrorGuaranteed; fn report_overflow_obligation<T>( &self, @@ -388,11 +382,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { } impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { - fn report_fulfillment_errors( - &self, - errors: &[FulfillmentError<'tcx>], - body_id: Option<hir::BodyId>, - ) -> ErrorGuaranteed { + fn report_fulfillment_errors(&self, errors: &[FulfillmentError<'tcx>]) -> ErrorGuaranteed { #[derive(Debug)] struct ErrorDescriptor<'tcx> { predicate: ty::Predicate<'tcx>, @@ -469,7 +459,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { for from_expansion in [false, true] { for (error, suppressed) in iter::zip(errors, &is_suppressed) { if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion { - self.report_fulfillment_error(error, body_id); + self.report_fulfillment_error(error); } } } @@ -955,8 +945,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); } - let body_hir_id = - self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); + let body_def_id = obligation.cause.body_id; // Try to report a help message if is_fn_trait && let Ok((implemented_kind, params)) = self.type_implements_fn_trait( @@ -1037,7 +1026,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if !self.report_similar_impl_candidates( impl_candidates, trait_ref, - body_hir_id, + body_def_id, &mut err, true, ) { @@ -1073,7 +1062,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.report_similar_impl_candidates( impl_candidates, trait_ref, - body_hir_id, + body_def_id, &mut err, true, ); @@ -1494,11 +1483,7 @@ trait InferCtxtPrivExt<'tcx> { // `error` occurring implies that `cond` occurs. fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool; - fn report_fulfillment_error( - &self, - error: &FulfillmentError<'tcx>, - body_id: Option<hir::BodyId>, - ); + fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>); fn report_projection_error( &self, @@ -1531,7 +1516,7 @@ trait InferCtxtPrivExt<'tcx> { &self, impl_candidates: Vec<ImplCandidate<'tcx>>, trait_ref: ty::PolyTraitRef<'tcx>, - body_id: hir::HirId, + body_def_id: LocalDefId, err: &mut Diagnostic, other: bool, ) -> bool; @@ -1561,11 +1546,7 @@ trait InferCtxtPrivExt<'tcx> { trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>, ) -> PredicateObligation<'tcx>; - fn maybe_report_ambiguity( - &self, - obligation: &PredicateObligation<'tcx>, - body_id: Option<hir::BodyId>, - ); + fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>); fn predicate_can_apply( &self, @@ -1647,11 +1628,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } #[instrument(skip(self), level = "debug")] - fn report_fulfillment_error( - &self, - error: &FulfillmentError<'tcx>, - body_id: Option<hir::BodyId>, - ) { + fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) { match error.code { FulfillmentErrorCode::CodeSelectionError(ref selection_error) => { self.report_selection_error( @@ -1664,7 +1641,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.report_projection_error(&error.obligation, e); } FulfillmentErrorCode::CodeAmbiguity => { - self.maybe_report_ambiguity(&error.obligation, body_id); + self.maybe_report_ambiguity(&error.obligation); } FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => { self.report_mismatched_types( @@ -2029,7 +2006,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { &self, impl_candidates: Vec<ImplCandidate<'tcx>>, trait_ref: ty::PolyTraitRef<'tcx>, - body_id: hir::HirId, + body_def_id: LocalDefId, err: &mut Diagnostic, other: bool, ) -> bool { @@ -2120,9 +2097,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // FIXME(compiler-errors): This could be generalized, both to // be more granular, and probably look past other `#[fundamental]` // types, too. - self.tcx - .visibility(def.did()) - .is_accessible_from(body_id.owner.def_id, self.tcx) + self.tcx.visibility(def.did()).is_accessible_from(body_def_id, self.tcx) } else { true } @@ -2231,11 +2206,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } #[instrument(skip(self), level = "debug")] - fn maybe_report_ambiguity( - &self, - obligation: &PredicateObligation<'tcx>, - body_id: Option<hir::BodyId>, - ) { + fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) { // Unable to successfully determine, probably means // insufficient type information, but could mean // ambiguous impls. The latter *ought* to be a @@ -2277,7 +2248,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { if let None = self.tainted_by_errors() { self.emit_inference_failure_err( - body_id, + obligation.cause.body_id, span, trait_ref.self_ty().skip_binder().into(), ErrorCode::E0282, @@ -2304,7 +2275,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let subst = data.trait_ref.substs.iter().find(|s| s.has_non_region_infer()); let mut err = if let Some(subst) = subst { - self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283, true) + self.emit_inference_failure_err( + obligation.cause.body_id, + span, + subst, + ErrorCode::E0283, + true, + ) } else { struct_span_err!( self.tcx.sess, @@ -2348,12 +2325,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { predicate.to_opt_poly_trait_pred().unwrap(), ); if impl_candidates.len() < 10 { - let hir = - self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); self.report_similar_impl_candidates( impl_candidates, trait_ref, - body_id.map(|id| id.hir_id).unwrap_or(hir), + obligation.cause.body_id, &mut err, false, ); @@ -2375,9 +2350,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); } - if let (Some(body_id), Some(ty::subst::GenericArgKind::Type(_))) = - (body_id, subst.map(|subst| subst.unpack())) + if let Some(ty::subst::GenericArgKind::Type(_)) = subst.map(|subst| subst.unpack()) { + let body_id = self.tcx.hir().body_owned_by(obligation.cause.body_id); let mut expr_finder = FindExprBySpan::new(span); expr_finder.visit_expr(&self.tcx.hir().body(body_id).value); @@ -2473,7 +2448,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return; } - self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282, false) + self.emit_inference_failure_err( + obligation.cause.body_id, + span, + arg, + ErrorCode::E0282, + false, + ) } ty::PredicateKind::Subtype(data) => { @@ -2487,7 +2468,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let SubtypePredicate { a_is_expected: _, a, b } = data; // both must be type variables, or the other would've been instantiated assert!(a.is_ty_var() && b.is_ty_var()); - self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282, true) + self.emit_inference_failure_err( + obligation.cause.body_id, + span, + a.into(), + ErrorCode::E0282, + true, + ) } ty::PredicateKind::Clause(ty::Clause::Projection(data)) => { if predicate.references_error() || self.tainted_by_errors().is_some() { @@ -2501,7 +2488,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .find(|g| g.has_non_region_infer()); if let Some(subst) = subst { let mut err = self.emit_inference_failure_err( - body_id, + obligation.cause.body_id, span, subst, ErrorCode::E0284, @@ -2530,7 +2517,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let subst = data.walk().find(|g| g.is_non_region_infer()); if let Some(subst) = subst { let err = self.emit_inference_failure_err( - body_id, + obligation.cause.body_id, span, subst, ErrorCode::E0284, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 62bad5b49b4..bfeda88a6d4 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -210,7 +210,7 @@ fn do_normalize_predicates<'tcx>( let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) { Ok(predicates) => predicates, Err(errors) => { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); return Err(reported); } }; diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 4da7c323492..a74a56bc5b2 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -172,7 +172,18 @@ impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0" #[stable(feature = "float_from_bool", since = "1.68.0")] #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")] impl const From<bool> for f32 { - /// Converts `bool` to `f32` losslessly. + /// Converts `bool` to `f32` losslessly. The resulting value is positive + /// `0.0` for `false` and `1.0` for `true` values. + /// + /// # Examples + /// ``` + /// let x: f32 = false.into(); + /// assert_eq!(x, 0.0); + /// assert!(x.is_sign_positive()); + /// + /// let y: f32 = true.into(); + /// assert_eq!(y, 1.0); + /// ``` #[inline] fn from(small: bool) -> Self { small as u8 as Self @@ -181,7 +192,18 @@ impl const From<bool> for f32 { #[stable(feature = "float_from_bool", since = "1.68.0")] #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")] impl const From<bool> for f64 { - /// Converts `bool` to `f64` losslessly. + /// Converts `bool` to `f64` losslessly. The resulting value is positive + /// `0.0` for `false` and `1.0` for `true` values. + /// + /// # Examples + /// ``` + /// let x: f64 = false.into(); + /// assert_eq!(x, 0.0); + /// assert!(x.is_sign_positive()); + /// + /// let y: f64 = true.into(); + /// assert_eq!(y, 1.0); + /// ``` #[inline] fn from(small: bool) -> Self { small as u8 as Self diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 1ad9af1549a..f41be46abc9 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -691,7 +691,7 @@ where #[inline(always)] #[must_use] #[unstable(feature = "ptr_from_ref", issue = "106116")] -pub fn from_ref<T: ?Sized>(r: &T) -> *const T { +pub const fn from_ref<T: ?Sized>(r: &T) -> *const T { r } @@ -702,7 +702,7 @@ pub fn from_ref<T: ?Sized>(r: &T) -> *const T { #[inline(always)] #[must_use] #[unstable(feature = "ptr_from_ref", issue = "106116")] -pub fn from_mut<T: ?Sized>(r: &mut T) -> *mut T { +pub const fn from_mut<T: ?Sized>(r: &mut T) -> *mut T { r } diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs index 5cb94c2f1d6..b79969663ca 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/format.rs @@ -165,8 +165,14 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { if !CiEnv::is_ci() && paths.is_empty() { match get_modified_rs_files(build) { Ok(Some(files)) => { + if files.len() <= 10 { + for file in &files { + println!("formatting modified file {file}"); + } + } else { + println!("formatting {} modified files", files.len()); + } for file in files { - println!("formatting modified file {file}"); ignore_fmt.add(&format!("/{file}")).expect(&file); } } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 909e7d83a15..7f6d80c91ad 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -216,7 +216,7 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool { /// Returns true if we're running in CI with modified LLVM (and thus can't download it) pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool { - CiEnv::is_ci() && { + CiEnv::is_ci() && config.rust_info.is_managed_git_subrepository() && { // We assume we have access to git, so it's okay to unconditionally pass // `true` here. let llvm_sha = detect_llvm_sha(config, true); diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh index cf784a66ae4..3939b4b7c41 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh @@ -32,24 +32,22 @@ cd solaris dpkg --add-architecture $APT_ARCH apt-get update -apt-get download $(apt-cache depends --recurse --no-replaces \ +apt-get install -y --download-only \ libc:$APT_ARCH \ - liblgrp-dev:$APT_ARCH \ liblgrp:$APT_ARCH \ libm-dev:$APT_ARCH \ libpthread:$APT_ARCH \ libresolv:$APT_ARCH \ librt:$APT_ARCH \ - libsendfile-dev:$APT_ARCH \ libsendfile:$APT_ARCH \ libsocket:$APT_ARCH \ system-crt:$APT_ARCH \ - system-header:$APT_ARCH \ - | grep "^\w") + system-header:$APT_ARCH -for deb in *$APT_ARCH.deb; do +for deb in /var/cache/apt/archives/*$APT_ARCH.deb; do dpkg -x $deb . done +apt-get clean # The -dev packages are not available from the apt repository we're using. # However, those packages are just symlinks from *.so to *.so.<version>. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index bbd9f18973a..29c3afe0d95 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2065,23 +2065,81 @@ fn clean_bare_fn_ty<'tcx>( BareFunctionDecl { unsafety: bare_fn.unsafety, abi: bare_fn.abi, decl, generic_params } } -/// This visitor is used to go through only the "top level" of a item and not enter any sub -/// item while looking for a given `Ident` which is stored into `item` if found. -struct OneLevelVisitor<'hir> { +/// Get DefId of of an item's user-visible parent. +/// +/// "User-visible" should account for re-exporting and inlining, which is why this function isn't +/// just `tcx.parent(def_id)`. If the provided `path` has more than one path element, the `DefId` +/// of the second-to-last will be given. +/// +/// ```text +/// use crate::foo::Bar; +/// ^^^ DefId of this item will be returned +/// ``` +/// +/// If the provided path has only one item, `tcx.parent(def_id)` will be returned instead. +fn get_path_parent_def_id( + tcx: TyCtxt<'_>, + def_id: DefId, + path: &hir::UsePath<'_>, +) -> Option<DefId> { + if let [.., parent_segment, _] = &path.segments { + match parent_segment.res { + hir::def::Res::Def(_, parent_def_id) => Some(parent_def_id), + _ if parent_segment.ident.name == kw::Crate => { + // In case the "parent" is the crate, it'll give `Res::Err` so we need to + // circumvent it this way. + Some(tcx.parent(def_id)) + } + _ => None, + } + } else { + // If the path doesn't have a parent, then the parent is the current module. + Some(tcx.parent(def_id)) + } +} + +/// This visitor is used to find an HIR Item based on its `use` path. This doesn't use the ordinary +/// name resolver because it does not walk all the way through a chain of re-exports. +pub(crate) struct OneLevelVisitor<'hir> { map: rustc_middle::hir::map::Map<'hir>, - item: Option<&'hir hir::Item<'hir>>, + pub(crate) item: Option<&'hir hir::Item<'hir>>, looking_for: Ident, target_def_id: LocalDefId, } impl<'hir> OneLevelVisitor<'hir> { - fn new(map: rustc_middle::hir::map::Map<'hir>, target_def_id: LocalDefId) -> Self { + pub(crate) fn new(map: rustc_middle::hir::map::Map<'hir>, target_def_id: LocalDefId) -> Self { Self { map, item: None, looking_for: Ident::empty(), target_def_id } } - fn reset(&mut self, looking_for: Ident) { - self.looking_for = looking_for; + pub(crate) fn find_target( + &mut self, + tcx: TyCtxt<'_>, + def_id: DefId, + path: &hir::UsePath<'_>, + ) -> Option<&'hir hir::Item<'hir>> { + let parent_def_id = get_path_parent_def_id(tcx, def_id, path)?; + let parent = self.map.get_if_local(parent_def_id)?; + + // We get the `Ident` we will be looking for into `item`. + self.looking_for = path.segments[path.segments.len() - 1].ident; + // We reset the `item`. self.item = None; + + match parent { + hir::Node::Item(parent_item) => { + hir::intravisit::walk_item(self, parent_item); + } + hir::Node::Crate(m) => { + hir::intravisit::walk_mod( + self, + m, + tcx.local_def_id_to_hir_id(parent_def_id.as_local().unwrap()), + ); + } + _ => return None, + } + self.item } } @@ -2129,41 +2187,7 @@ fn get_all_import_attributes<'hir>( add_without_unwanted_attributes(attributes, hir_map.attrs(item.hir_id()), is_inline); } - let def_id = if let [.., parent_segment, _] = &path.segments { - match parent_segment.res { - hir::def::Res::Def(_, def_id) => def_id, - _ if parent_segment.ident.name == kw::Crate => { - // In case the "parent" is the crate, it'll give `Res::Err` so we need to - // circumvent it this way. - tcx.parent(item.owner_id.def_id.to_def_id()) - } - _ => break, - } - } else { - // If the path doesn't have a parent, then the parent is the current module. - tcx.parent(item.owner_id.def_id.to_def_id()) - }; - - let Some(parent) = hir_map.get_if_local(def_id) else { break }; - - // We get the `Ident` we will be looking for into `item`. - let looking_for = path.segments[path.segments.len() - 1].ident; - visitor.reset(looking_for); - - match parent { - hir::Node::Item(parent_item) => { - hir::intravisit::walk_item(&mut visitor, parent_item); - } - hir::Node::Crate(m) => { - hir::intravisit::walk_mod( - &mut visitor, - m, - tcx.local_def_id_to_hir_id(def_id.as_local().unwrap()), - ); - } - _ => break, - } - if let Some(i) = visitor.item { + if let Some(i) = visitor.find_target(tcx, item.owner_id.def_id.to_def_id(), path) { item = i; } else { break; diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 1030fe74747..ed1eb66b97c 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -647,11 +647,35 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { </noscript>\ <link rel=\"stylesheet\" \ href=\"{static_root_path}{settings_css}\">\ - <script defer src=\"{static_root_path}{settings_js}\"></script>", + <script defer src=\"{static_root_path}{settings_js}\"></script>\ + <link rel=\"preload\" href=\"{static_root_path}{theme_light_css}\" \ + as=\"style\">\ + <link rel=\"preload\" href=\"{static_root_path}{theme_dark_css}\" \ + as=\"style\">\ + <link rel=\"preload\" href=\"{static_root_path}{theme_ayu_css}\" \ + as=\"style\">", static_root_path = page.get_static_root_path(), settings_css = static_files::STATIC_FILES.settings_css, settings_js = static_files::STATIC_FILES.settings_js, - ) + theme_light_css = static_files::STATIC_FILES.theme_light_css, + theme_dark_css = static_files::STATIC_FILES.theme_dark_css, + theme_ayu_css = static_files::STATIC_FILES.theme_ayu_css, + ); + // Pre-load all theme CSS files, so that switching feels seamless. + // + // When loading settings.html as a popover, the equivalent HTML is + // generated in main.js. + for file in &shared.style_files { + if let Ok(theme) = file.basename() { + write!( + buf, + "<link rel=\"preload\" href=\"{root_path}{theme}{suffix}.css\" \ + as=\"style\">", + root_path = page.static_root_path.unwrap_or(""), + suffix = page.resource_suffix, + ); + } + } }, &shared.style_files, ); diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 4514894cabe..eb9262f472b 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -29,12 +29,12 @@ pub(crate) enum LinkFromSrc { /// This function will do at most two things: /// -/// 1. Generate a `span` correspondance map which links an item `span` to its definition `span`. +/// 1. Generate a `span` correspondence map which links an item `span` to its definition `span`. /// 2. Collect the source code files. /// -/// It returns the `krate`, the source code files and the `span` correspondance map. +/// It returns the `krate`, the source code files and the `span` correspondence map. /// -/// Note about the `span` correspondance map: the keys are actually `(lo, hi)` of `span`s. We don't +/// Note about the `span` correspondence map: the keys are actually `(lo, hi)` of `span`s. We don't /// need the `span` context later on, only their position, so instead of keep a whole `Span`, we /// only keep the `lo` and `hi`. pub(crate) fn collect_spans_and_sources( diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 5e8c0e8d10c..403b5004d65 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1,20 +1,9 @@ // Local js definitions: /* global addClass, getSettingValue, hasClass, searchState */ -/* global onEach, onEachLazy, removeClass */ +/* global onEach, onEachLazy, removeClass, getVar */ "use strict"; -// Get a value from the rustdoc-vars div, which is used to convey data from -// Rust to the JS. If there is no such element, return null. -function getVar(name) { - const el = document.getElementById("rustdoc-vars"); - if (el) { - return el.attributes["data-" + name].value; - } else { - return null; - } -} - // Given a basename (e.g. "storage") and an extension (e.g. ".js"), return a URL // for a resource under the root-path, with the resource-suffix. function resourcePath(basename, extension) { @@ -187,6 +176,15 @@ function loadCss(cssUrl) { document.getElementsByTagName("head")[0].appendChild(link); } +function preLoadCss(cssUrl) { + // https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload + const link = document.createElement("link"); + link.href = cssUrl; + link.rel = "preload"; + link.as = "style"; + document.getElementsByTagName("head")[0].appendChild(link); +} + (function() { const isHelpPage = window.location.pathname.endsWith("/help.html"); @@ -207,6 +205,23 @@ function loadCss(cssUrl) { // hopefully be loaded when the JS will generate the settings content. loadCss(getVar("static-root-path") + getVar("settings-css")); loadScript(getVar("static-root-path") + getVar("settings-js")); + preLoadCss(getVar("static-root-path") + getVar("theme-light-css")); + preLoadCss(getVar("static-root-path") + getVar("theme-dark-css")); + preLoadCss(getVar("static-root-path") + getVar("theme-ayu-css")); + // Pre-load all theme CSS files, so that switching feels seamless. + // + // When loading settings.html as a standalone page, the equivalent HTML is + // generated in context.rs. + setTimeout(() => { + const themes = getVar("themes").split(","); + for (const theme of themes) { + // if there are no themes, do nothing + // "".split(",") == [""] + if (theme !== "") { + preLoadCss(getVar("root-path") + theme + ".css"); + } + } + }, 0); }; window.searchState = { diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index c72ac254fc0..c3fed9a72d4 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -7,7 +7,6 @@ const darkThemes = ["dark", "ayu"]; window.currentTheme = document.getElementById("themeStyle"); -window.mainTheme = document.getElementById("mainThemeStyle"); // WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY // If you update this line, then you also need to update the media query with the same @@ -44,8 +43,6 @@ function getSettingValue(settingName) { const localStoredTheme = getSettingValue("theme"); -const savedHref = []; - // eslint-disable-next-line no-unused-vars function hasClass(elem, className) { return elem && elem.classList && elem.classList.contains(className); @@ -102,6 +99,7 @@ function onEach(arr, func, reversed) { * @param {function(?)} func - The callback * @param {boolean} [reversed] - Whether to iterate in reverse */ +// eslint-disable-next-line no-unused-vars function onEachLazy(lazyArray, func, reversed) { return onEach( Array.prototype.slice.call(lazyArray), @@ -125,30 +123,37 @@ function getCurrentValue(name) { } } -function switchTheme(styleElem, mainStyleElem, newThemeName, saveTheme) { +// Get a value from the rustdoc-vars div, which is used to convey data from +// Rust to the JS. If there is no such element, return null. +const getVar = (function getVar(name) { + const el = document.getElementById("rustdoc-vars"); + if (el) { + return el.attributes["data-" + name].value; + } else { + return null; + } +}); + +function switchTheme(newThemeName, saveTheme) { // If this new value comes from a system setting or from the previously // saved theme, no need to save it. if (saveTheme) { updateLocalStorage("theme", newThemeName); } - if (savedHref.length === 0) { - onEachLazy(document.getElementsByTagName("link"), el => { - savedHref.push(el.href); - }); + let newHref; + + if (newThemeName === "light" || newThemeName === "dark" || newThemeName === "ayu") { + newHref = getVar("static-root-path") + getVar("theme-" + newThemeName + "-css"); + } else { + newHref = getVar("root-path") + newThemeName + getVar("resource-suffix") + ".css"; } - const newHref = savedHref.find(url => { - const m = url.match(/static\.files\/(.*)-[a-f0-9]{16}\.css$/); - if (m && m[1] === newThemeName) { - return true; - } - const m2 = url.match(/\/([^/]*)\.css$/); - if (m2 && m2[1].startsWith(newThemeName)) { - return true; - } - }); - if (newHref && newHref !== styleElem.href) { - styleElem.href = newHref; + + if (!window.currentTheme) { + document.write(`<link rel="stylesheet" id="themeStyle" href="${newHref}">`); + window.currentTheme = document.getElementById("themeStyle"); + } else if (newHref !== window.currentTheme.href) { + window.currentTheme.href = newHref; } } @@ -164,7 +169,7 @@ const updateTheme = (function() { */ function updateTheme() { const use = (theme, saveTheme) => { - switchTheme(window.currentTheme, window.mainTheme, theme, saveTheme); + switchTheme(theme, saveTheme); }; // maybe the user has disabled the setting in the meantime! diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index e896850fab6..532660e3d33 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -17,12 +17,6 @@ <link rel="stylesheet" {#+ #} href="{{static_root_path|safe}}{{files.rustdoc_css}}" {#+ #} id="mainThemeStyle"> {# #} - <link rel="stylesheet" id="themeStyle" href="{{static_root_path|safe}}{{files.theme_light_css}}"> {# #} - <link rel="stylesheet" disabled href="{{static_root_path|safe}}{{files.theme_dark_css}}"> {# #} - <link rel="stylesheet" disabled href="{{static_root_path|safe}}{{files.theme_ayu_css}}"> {# #} - {% for theme in themes %} - <link rel="stylesheet" disabled href="{{page.root_path|safe}}{{theme}}{{page.resource_suffix}}.css"> {# #} - {% endfor %} {% if !layout.default_settings.is_empty() %} <script id="default-settings" {#+ #} {%~ for (k, v) in layout.default_settings ~%} @@ -30,6 +24,21 @@ {% endfor %} ></script> {# #} {% endif %} + <div id="rustdoc-vars" {#+ #} + data-root-path="{{page.root_path|safe}}" {#+ #} + data-static-root-path="{{static_root_path|safe}}" {#+ #} + data-current-crate="{{layout.krate}}" {#+ #} + data-themes="{{themes|join(",") }}" {#+ #} + data-resource-suffix="{{page.resource_suffix}}" {#+ #} + data-rustdoc-version="{{rustdoc_version}}" {#+ #} + data-search-js="{{files.search_js}}" {#+ #} + data-settings-js="{{files.settings_js}}" {#+ #} + data-settings-css="{{files.settings_css}}" {#+ #} + data-theme-light-css="{{files.theme_light_css}}" {#+ #} + data-theme-dark-css="{{files.theme_dark_css}}" {#+ #} + data-theme-ayu-css="{{files.theme_ayu_css}}" {#+ #} + > {# #} + </div> {# #} <script src="{{static_root_path|safe}}{{files.storage_js}}"></script> {# #} {% if page.css_class.contains("crate") %} <script defer src="{{page.root_path|safe}}crates{{page.resource_suffix}}.js"></script> {# #} @@ -45,6 +54,12 @@ {% endif %} <noscript> {# #} <link rel="stylesheet" {#+ #} + media="(prefers-color-scheme:light)" {#+ #} + href="{{static_root_path|safe}}{{files.theme_light_css}}"> {# #} + <link rel="stylesheet" {#+ #} + media="(prefers-color-scheme:dark)" {#+ #} + href="{{static_root_path|safe}}{{files.theme_dark_css}}"> {# #} + <link rel="stylesheet" {#+ #} href="{{static_root_path|safe}}{{files.noscript_css}}"> {# #} </noscript> {# #} {% if layout.css_file_extension.is_some() %} @@ -132,17 +147,5 @@ {% if page.css_class != "source" %}</div>{% endif %} </main> {# #} {{ layout.external_html.after_content|safe }} - <div id="rustdoc-vars" {#+ #} - data-root-path="{{page.root_path|safe}}" {#+ #} - data-static-root-path="{{static_root_path|safe}}" {#+ #} - data-current-crate="{{layout.krate}}" {#+ #} - data-themes="{{themes|join(",") }}" {#+ #} - data-resource-suffix="{{page.resource_suffix}}" {#+ #} - data-rustdoc-version="{{rustdoc_version}}" {#+ #} - data-search-js="{{files.search_js}}" {#+ #} - data-settings-js="{{files.settings_js}}" {#+ #} - data-settings-css="{{files.settings_css}}" {#+ #} - > {# #} - </div> {# #} </body> {# #} </html> {# #} diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 5bbbff175cf..e09a68069e8 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -15,7 +15,7 @@ use rustc_span::Span; use std::mem; -use crate::clean::{cfg::Cfg, AttributesExt, NestedAttributesExt}; +use crate::clean::{cfg::Cfg, AttributesExt, NestedAttributesExt, OneLevelVisitor}; use crate::core; /// This module is used to store stuff from Rust's AST in a more convenient @@ -220,9 +220,15 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { renamed: Option<Symbol>, glob: bool, please_inline: bool, + path: &hir::UsePath<'_>, ) -> bool { debug!("maybe_inline_local res: {:?}", res); + if renamed == Some(kw::Underscore) { + // We never inline `_` reexports. + return false; + } + if self.cx.output_format.is_json() { return false; } @@ -263,6 +269,22 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { return false; } + if !please_inline && + let mut visitor = OneLevelVisitor::new(self.cx.tcx.hir(), res_did) && + let Some(item) = visitor.find_target(self.cx.tcx, def_id.to_def_id(), path) && + let item_def_id = item.owner_id.def_id && + item_def_id != def_id && + self + .cx + .cache + .effective_visibilities + .is_directly_public(self.cx.tcx, item_def_id.to_def_id()) && + !inherits_doc_hidden(self.cx.tcx, item_def_id) + { + // The imported item is public and not `doc(hidden)` so no need to inline it. + return false; + } + let ret = match tcx.hir().get_by_def_id(res_did) { Node::Item(&hir::Item { kind: hir::ItemKind::Mod(ref m), .. }) if glob => { let prev = mem::replace(&mut self.inlining, true); @@ -329,8 +351,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { self.visit_foreign_item_inner(item, None); } } - // If we're inlining, skip private items or item reexported as "_". - _ if self.inlining && (!is_pub || renamed == Some(kw::Underscore)) => {} + // If we're inlining, skip private items. + _ if self.inlining && !is_pub => {} hir::ItemKind::GlobalAsm(..) => {} hir::ItemKind::Use(_, hir::UseKind::ListStem) => {} hir::ItemKind::Use(path, kind) => { @@ -361,6 +383,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { ident, is_glob, please_inline, + path, ) { continue; } diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index 33938ac9a0a..6d6d3c89a3c 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -62,6 +62,8 @@ const EXCEPTION_PATHS: &[&str] = &[ "library/std/src/panic.rs", // fuchsia-specific panic backtrace handling "library/std/src/personality.rs", "library/std/src/personality/", + "library/std/src/thread/mod.rs", + "library/std/src/thread/local.rs", ]; pub fn check(path: &Path, bad: &mut bool) { @@ -128,6 +130,7 @@ fn check_cfgs( || cfg.contains("target_env") || cfg.contains("target_abi") || cfg.contains("target_vendor") + || cfg.contains("target_family") || cfg.contains("unix") || cfg.contains("windows"); diff --git a/tests/run-make-fulldeps/rustdoc-themes/foo.rs b/tests/run-make-fulldeps/rustdoc-themes/foo.rs index 58efaf7d5a0..995544aeff9 100644 --- a/tests/run-make-fulldeps/rustdoc-themes/foo.rs +++ b/tests/run-make-fulldeps/rustdoc-themes/foo.rs @@ -1,4 +1,4 @@ // @has test.css // @has foo/struct.Foo.html -// @has - '//link[@rel="stylesheet"]/@href' '../test.css' +// @has - '//*[@id="rustdoc-vars"]/@data-themes' 'test' pub struct Foo; diff --git a/tests/rustdoc-gui/scrape-examples-button-focus.goml b/tests/rustdoc-gui/scrape-examples-button-focus.goml index 1b5c3a0d202..16f0ced8c6e 100644 --- a/tests/rustdoc-gui/scrape-examples-button-focus.goml +++ b/tests/rustdoc-gui/scrape-examples-button-focus.goml @@ -8,24 +8,24 @@ focus: ".scraped-example-list > .scraped-example .next" press-key: "Enter" assert-property-false: (".scraped-example-list > .scraped-example pre", { "scrollTop": |initialScrollTop| -}) +}, NEAR) focus: ".scraped-example-list > .scraped-example .prev" press-key: "Enter" assert-property: (".scraped-example-list > .scraped-example pre", { "scrollTop": |initialScrollTop| -}) +}, NEAR) // The expand button increases the scrollHeight of the minimized code viewport store-property: (smallOffsetHeight, ".scraped-example-list > .scraped-example pre", "offsetHeight") assert-property-false: (".scraped-example-list > .scraped-example pre", { "scrollHeight": |smallOffsetHeight| -}) +}, NEAR) focus: ".scraped-example-list > .scraped-example .expand" press-key: "Enter" assert-property-false: (".scraped-example-list > .scraped-example pre", { "offsetHeight": |smallOffsetHeight| -}) +}, NEAR) store-property: (fullOffsetHeight, ".scraped-example-list > .scraped-example pre", "offsetHeight") assert-property: (".scraped-example-list > .scraped-example pre", { "scrollHeight": |fullOffsetHeight| -}) +}, NEAR) diff --git a/tests/rustdoc/anonymous-reexport.rs b/tests/rustdoc/anonymous-reexport.rs index 6b884ff14df..839c1a30346 100644 --- a/tests/rustdoc/anonymous-reexport.rs +++ b/tests/rustdoc/anonymous-reexport.rs @@ -4,9 +4,13 @@ // @has 'foo/index.html' // @has - '//*[@id="main-content"]' '' -// We check that the only "h2" present is for "Bla". -// @count - '//*[@id="main-content"]/h2' 1 +// We check that the only "h2" present are "Structs" (for "Bla") and "Re-exports". +// @count - '//*[@id="main-content"]/h2' 2 // @has - '//*[@id="main-content"]/h2' 'Structs' +// @has - '//*[@id="main-content"]/h2' 'Re-exports' +// The 3 re-exports. +// @count - '//*[@id="main-content"]//*[@class="item-table"]//li//code' 3 +// The public struct. // @count - '//*[@id="main-content"]//a[@class="struct"]' 1 mod ext { diff --git a/tests/rustdoc/issue-108679-reexport-of-reexport.rs b/tests/rustdoc/issue-108679-reexport-of-reexport.rs new file mode 100644 index 00000000000..5f977801cfd --- /dev/null +++ b/tests/rustdoc/issue-108679-reexport-of-reexport.rs @@ -0,0 +1,29 @@ +// This test ensures that the `struct.B.html` only exists in `a`: +// since `a::B` is public (and inlined too), `self::a::B` doesn't +// need to be inlined as well. + +#![crate_name = "foo"] + +pub mod a { + // @has 'foo/a/index.html' + // Should only contain "Structs". + // @count - '//*[@id="main-content"]//*[@class="item-table"]' 1 + // @has - '//*[@id="structs"]' 'Structs' + // @has - '//*[@id="main-content"]//a[@href="struct.A.html"]' 'A' + // @has - '//*[@id="main-content"]//a[@href="struct.B.html"]' 'B' + mod b { + pub struct B; + } + pub use self::b::B; + pub struct A; +} + +// @has 'foo/index.html' +// @!has - '//*[@id="structs"]' 'Structs' +// @has - '//*[@id="reexports"]' 'Re-exports' +// @has - '//*[@id="modules"]' 'Modules' +// @has - '//*[@id="main-content"]//*[@id="reexport.A"]' 'pub use self::a::A;' +// @has - '//*[@id="main-content"]//*[@id="reexport.B"]' 'pub use self::a::B;' +// Should only contain "Modules" and "Re-exports". +// @count - '//*[@id="main-content"]//*[@class="item-table"]' 2 +pub use self::a::{A, B}; diff --git a/tests/rustdoc/issue-108931-anonymous-reexport.rs b/tests/rustdoc/issue-108931-anonymous-reexport.rs new file mode 100644 index 00000000000..302f7413398 --- /dev/null +++ b/tests/rustdoc/issue-108931-anonymous-reexport.rs @@ -0,0 +1,21 @@ +// Ensuring that anonymous re-exports are always inlined. + +#![crate_name = "foo"] + +pub mod foo { + pub struct Foo; +} + +mod bar { + pub struct Bar; +} + +// @has 'foo/index.html' +// We check that the only "h2" present are "Re-exports" and "Modules". +// @count - '//*[@id="main-content"]/h2' 2 +// @has - '//*[@id="main-content"]/h2' 'Re-exports' +// @has - '//*[@id="main-content"]/h2' 'Modules' +// @has - '//*[@id="main-content"]//*[@class="item-table"]//li//code' 'pub use foo::Foo as _;' +// @has - '//*[@id="main-content"]//*[@class="item-table"]//li//code' 'pub use bar::Bar as _;' +pub use foo::Foo as _; +pub use bar::Bar as _; diff --git a/tests/ui/parser/integer-literal-start-ident.rs b/tests/ui/parser/integer-literal-start-ident.rs new file mode 100644 index 00000000000..12537482e0f --- /dev/null +++ b/tests/ui/parser/integer-literal-start-ident.rs @@ -0,0 +1,2 @@ +fn 1main() {} +//~^ ERROR expected identifier, found `1main` diff --git a/tests/ui/parser/integer-literal-start-ident.stderr b/tests/ui/parser/integer-literal-start-ident.stderr new file mode 100644 index 00000000000..51c37a0d24c --- /dev/null +++ b/tests/ui/parser/integer-literal-start-ident.stderr @@ -0,0 +1,10 @@ +error: expected identifier, found `1main` + --> $DIR/integer-literal-start-ident.rs:1:4 + | +LL | fn 1main() {} + | ^^^^^ expected identifier + | + = help: identifiers cannot start with a number + +error: aborting due to previous error + diff --git a/tests/ui/parser/issues/issue-104088.rs b/tests/ui/parser/issues/issue-104088.rs index 5f794fe2dc9..86988c8cd21 100644 --- a/tests/ui/parser/issues/issue-104088.rs +++ b/tests/ui/parser/issues/issue-104088.rs @@ -4,12 +4,12 @@ fn test() { fn test_2() { let 1x = 123; - //~^ ERROR expected identifier, found number literal + //~^ ERROR expected identifier, found `1x` } fn test_3() { let 2x: i32 = 123; - //~^ ERROR expected identifier, found number literal + //~^ ERROR expected identifier, found `2x` } fn test_4() { @@ -20,7 +20,7 @@ fn test_4() { fn test_5() { let 23name = 123; - //~^ ERROR expected identifier, found number literal + //~^ ERROR expected identifier, found `23name` } fn main() {} diff --git a/tests/ui/parser/issues/issue-104088.stderr b/tests/ui/parser/issues/issue-104088.stderr index ff4b4bdb695..6511a313149 100644 --- a/tests/ui/parser/issues/issue-104088.stderr +++ b/tests/ui/parser/issues/issue-104088.stderr @@ -1,20 +1,26 @@ -error: expected identifier, found number literal +error: expected identifier, found `1x` --> $DIR/issue-104088.rs:6:9 | LL | let 1x = 123; - | ^^ identifiers cannot start with a number + | ^^ expected identifier + | + = help: identifiers cannot start with a number -error: expected identifier, found number literal +error: expected identifier, found `2x` --> $DIR/issue-104088.rs:11:9 | LL | let 2x: i32 = 123; - | ^^ identifiers cannot start with a number + | ^^ expected identifier + | + = help: identifiers cannot start with a number -error: expected identifier, found number literal +error: expected identifier, found `23name` --> $DIR/issue-104088.rs:22:9 | LL | let 23name = 123; - | ^^^^^^ identifiers cannot start with a number + | ^^^^^^ expected identifier + | + = help: identifiers cannot start with a number error[E0308]: mismatched types --> $DIR/issue-104088.rs:16:12 diff --git a/tests/ui/suggestions/correct-binder-for-arbitrary-bound-sugg.rs b/tests/ui/suggestions/correct-binder-for-arbitrary-bound-sugg.rs new file mode 100644 index 00000000000..e56c8622ece --- /dev/null +++ b/tests/ui/suggestions/correct-binder-for-arbitrary-bound-sugg.rs @@ -0,0 +1,16 @@ +trait Foo +where + for<'a> &'a Self: Bar, +{ +} + +impl Foo for () {} + +trait Bar {} + +impl Bar for &() {} + +fn foo<T: Foo>() {} +//~^ ERROR the trait bound `for<'a> &'a T: Bar` is not satisfied + +fn main() {} diff --git a/tests/ui/suggestions/correct-binder-for-arbitrary-bound-sugg.stderr b/tests/ui/suggestions/correct-binder-for-arbitrary-bound-sugg.stderr new file mode 100644 index 00000000000..2298e7f4e0c --- /dev/null +++ b/tests/ui/suggestions/correct-binder-for-arbitrary-bound-sugg.stderr @@ -0,0 +1,22 @@ +error[E0277]: the trait bound `for<'a> &'a T: Bar` is not satisfied + --> $DIR/correct-binder-for-arbitrary-bound-sugg.rs:13:11 + | +LL | fn foo<T: Foo>() {} + | ^^^ the trait `for<'a> Bar` is not implemented for `&'a T` + | +note: required by a bound in `Foo` + --> $DIR/correct-binder-for-arbitrary-bound-sugg.rs:3:23 + | +LL | trait Foo + | --- required by a bound in this trait +LL | where +LL | for<'a> &'a Self: Bar, + | ^^^ required by this bound in `Foo` +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | fn foo<T: Foo>() where for<'a> &'a T: Bar {} + | ++++++++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/triagebot.toml b/triagebot.toml index 403a7087ee1..e39a0b06b97 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -451,6 +451,10 @@ cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@TaKO8Ki"] message = "`rustc_macros::diagnostics` was changed" cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@TaKO8Ki"] +[mentions."compiler/rustc_smir"] +message = "This PR changes Stable MIR" +cc = ["@oli-obk", "@celinval"] + [mentions."compiler/rustc_target/src/spec"] message = """ These commits modify **compiler targets**. @@ -497,6 +501,7 @@ compiler-team-contributors = [ "@TaKO8Ki", "@Nilstrieb", "@WaffleLapkin", + "@b-naber", ] compiler = [ "compiler-team", |
