diff --git a/Cargo.lock b/Cargo.lock index 92e6a22b4b91..6e86f6c02f17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,9 +7,18 @@ name = "addr2line" version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli 0.28.1", +] + +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "compiler_builtins", - "gimli", + "gimli 0.29.0", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -287,7 +296,7 @@ version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ - "addr2line", + "addr2line 0.21.0", "cc", "cfg-if", "libc", @@ -1575,6 +1584,17 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + [[package]] name = "glob" version = "0.3.1" @@ -3234,7 +3254,7 @@ dependencies = [ name = "run_make_support" version = "0.0.0" dependencies = [ - "gimli", + "gimli 0.28.1", "object 0.34.0", "regex", "similar", @@ -4686,6 +4706,7 @@ dependencies = [ "rustc_span", "rustc_type_ir_macros", "smallvec", + "tracing", ] [[package]] @@ -5129,7 +5150,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" name = "std" version = "0.0.0" dependencies = [ - "addr2line", + "addr2line 0.22.0", "alloc", "cfg-if", "compiler_builtins", @@ -5408,7 +5429,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4db52ee8fec06e119b692ef3dd2c4cf621a99204c1b8c47407870ed050305b9b" dependencies = [ - "gimli", + "gimli 0.28.1", "hashbrown", "object 0.32.2", "tracing", @@ -5908,7 +5929,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b" dependencies = [ "compiler_builtins", - "gimli", + "gimli 0.28.1", "rustc-std-workspace-core", ] diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 5d7eb0525615..f372d3a05226 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -294,12 +294,13 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } -/// Returns `rhs` sufficiently masked, truncated, and/or extended so that -/// it can be used to shift `lhs`. +/// Returns `rhs` sufficiently masked, truncated, and/or extended so that it can be used to shift +/// `lhs`: it has the same size as `lhs`, and the value, when interpreted unsigned (no matter its +/// type), will not exceed the size of `lhs`. /// -/// Shifts in MIR are all allowed to have mismatched LHS & RHS types. +/// Shifts in MIR are all allowed to have mismatched LHS & RHS types, and signed RHS. /// The shift methods in `BuilderMethods`, however, are fully homogeneous -/// (both parameters and the return type are all the same type). +/// (both parameters and the return type are all the same size) and assume an unsigned RHS. /// /// If `is_unchecked` is false, this masks the RHS to ensure it stays in-bounds, /// as the `BuilderMethods` shifts are UB for out-of-bounds shift amounts. diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 9fd6eb8edab3..2f0daefa46a6 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -110,8 +110,16 @@ pub trait BuilderMethods<'a, 'tcx>: fn frem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn frem_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn frem_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; + /// Generate a left-shift. Both operands must have the same size. The right operand must be + /// interpreted as unsigned and can be assumed to be less than the size of the left operand. fn shl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; + /// Generate a logical right-shift. Both operands must have the same size. The right operand + /// must be interpreted as unsigned and can be assumed to be less than the size of the left + /// operand. fn lshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; + /// Generate an arithmetic right-shift. Both operands must have the same size. The right operand + /// must be interpreted as unsigned and can be assumed to be less than the size of the left + /// operand. fn ashr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn unchecked_sadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn unchecked_uadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index d99ecb610852..5d3ba5d32230 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -223,7 +223,8 @@ fn expand_macro<'cx>( let arm_span = rhses[i].span(); // rhs has holes ( `$id` and `$(...)` that need filled) - let tts = match transcribe(cx, &named_matches, rhs, rhs_span, transparency) { + let id = cx.current_expansion.id; + let tts = match transcribe(psess, &named_matches, rhs, rhs_span, transparency, id) { Ok(tts) => tts, Err(err) => { let guar = err.emit(); diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 8a084dcb4fe3..e1f50876b058 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -1,4 +1,3 @@ -use crate::base::ExtCtxt; use crate::errors::{ CountRepetitionMisplaced, MetaVarExprUnrecognizedVar, MetaVarsDifSeqMatchers, MustRepeatOnce, NoSyntaxVarsExprRepeat, VarStillRepeating, @@ -9,12 +8,13 @@ use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{pluralize, Diag, PResult}; +use rustc_errors::{pluralize, Diag, DiagCtxt, PResult}; use rustc_parse::parser::ParseNtResult; use rustc_span::hygiene::{LocalExpnId, Transparency}; use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent}; use rustc_span::{with_metavar_spans, Span, SyntaxContext}; +use rustc_session::parse::ParseSess; use smallvec::{smallvec, SmallVec}; use std::mem; @@ -99,11 +99,12 @@ impl<'a> Iterator for Frame<'a> { /// /// Along the way, we do some additional error checking. pub(super) fn transcribe<'a>( - cx: &ExtCtxt<'a>, + psess: &'a ParseSess, interp: &FxHashMap, src: &mbe::Delimited, src_span: DelimSpan, transparency: Transparency, + expand_id: LocalExpnId, ) -> PResult<'a, TokenStream> { // Nothing for us to transcribe... if src.tts.is_empty() { @@ -137,8 +138,9 @@ pub(super) fn transcribe<'a>( // again, and we are done transcribing. let mut result: Vec = Vec::new(); let mut result_stack = Vec::new(); - let mut marker = Marker(cx.current_expansion.id, transparency, Default::default()); + let mut marker = Marker(expand_id, transparency, Default::default()); + let dcx = &psess.dcx; loop { // Look at the last frame on the stack. // If it still has a TokenTree we have not looked at yet, use that tree. @@ -201,9 +203,7 @@ pub(super) fn transcribe<'a>( seq @ mbe::TokenTree::Sequence(_, seq_rep) => { match lockstep_iter_size(seq, interp, &repeats) { LockstepIterSize::Unconstrained => { - return Err(cx - .dcx() - .create_err(NoSyntaxVarsExprRepeat { span: seq.span() })); + return Err(dcx.create_err(NoSyntaxVarsExprRepeat { span: seq.span() })); } LockstepIterSize::Contradiction(msg) => { @@ -211,9 +211,9 @@ pub(super) fn transcribe<'a>( // happens when two meta-variables are used in the same repetition in a // sequence, but they come from different sequence matchers and repeat // different amounts. - return Err(cx - .dcx() - .create_err(MetaVarsDifSeqMatchers { span: seq.span(), msg })); + return Err( + dcx.create_err(MetaVarsDifSeqMatchers { span: seq.span(), msg }) + ); } LockstepIterSize::Constraint(len, _) => { @@ -227,9 +227,7 @@ pub(super) fn transcribe<'a>( // FIXME: this really ought to be caught at macro definition // time... It happens when the Kleene operator in the matcher and // the body for the same meta-variable do not match. - return Err(cx - .dcx() - .create_err(MustRepeatOnce { span: sp.entire() })); + return Err(dcx.create_err(MustRepeatOnce { span: sp.entire() })); } } else { // 0 is the initial counter (we have done 0 repetitions so far). `len` @@ -274,7 +272,7 @@ pub(super) fn transcribe<'a>( MatchedSingle(ParseNtResult::Tt(tt)) => { // `tt`s are emitted into the output stream directly as "raw tokens", // without wrapping them into groups. - maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker) + maybe_use_metavar_location(psess, &stack, sp, tt, &mut marker) } MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => { marker.visit_span(&mut sp); @@ -295,7 +293,7 @@ pub(super) fn transcribe<'a>( } MatchedSeq(..) => { // We were unable to descend far enough. This is an error. - return Err(cx.dcx().create_err(VarStillRepeating { span: sp, ident })); + return Err(dcx.create_err(VarStillRepeating { span: sp, ident })); } }; result.push(tt) @@ -314,7 +312,7 @@ pub(super) fn transcribe<'a>( // Replace meta-variable expressions with the result of their expansion. mbe::TokenTree::MetaVarExpr(sp, expr) => { - transcribe_metavar_expr(cx, expr, interp, &mut marker, &repeats, &mut result, sp)?; + transcribe_metavar_expr(dcx, expr, interp, &mut marker, &repeats, &mut result, sp)?; } // If we are entering a new delimiter, we push its contents to the `stack` to be @@ -374,7 +372,7 @@ pub(super) fn transcribe<'a>( /// combine with each other and not with tokens outside of the sequence. /// - The metavariable span comes from a different crate, then we prefer the more local span. fn maybe_use_metavar_location( - cx: &ExtCtxt<'_>, + psess: &ParseSess, stack: &[Frame<'_>], mut metavar_span: Span, orig_tt: &TokenTree, @@ -412,7 +410,7 @@ fn maybe_use_metavar_location( && insert(mspans, dspan.entire(), metavar_span) }), }; - if no_collision || cx.source_map().is_imported(metavar_span) { + if no_collision || psess.source_map().is_imported(metavar_span) { return orig_tt.clone(); } @@ -573,7 +571,7 @@ fn lockstep_iter_size( /// * `[ $( ${count(foo, 1)} ),* ]` will return an error because `${count(foo, 1)}` is /// declared inside a single repetition and the index `1` implies two nested repetitions. fn count_repetitions<'a>( - cx: &ExtCtxt<'a>, + dcx: &'a DiagCtxt, depth_user: usize, mut matched: &NamedMatch, repeats: &[(usize, usize)], @@ -610,7 +608,7 @@ fn count_repetitions<'a>( .and_then(|el| el.checked_sub(repeats.len())) .unwrap_or_default(); if depth_user > depth_max { - return Err(out_of_bounds_err(cx, depth_max + 1, sp.entire(), "count")); + return Err(out_of_bounds_err(dcx, depth_max + 1, sp.entire(), "count")); } // `repeats` records all of the nested levels at which we are currently @@ -626,7 +624,7 @@ fn count_repetitions<'a>( } if let MatchedSingle(_) = matched { - return Err(cx.dcx().create_err(CountRepetitionMisplaced { span: sp.entire() })); + return Err(dcx.create_err(CountRepetitionMisplaced { span: sp.entire() })); } count(depth_user, depth_max, matched) @@ -634,7 +632,7 @@ fn count_repetitions<'a>( /// Returns a `NamedMatch` item declared on the LHS given an arbitrary [Ident] fn matched_from_ident<'ctx, 'interp, 'rslt>( - cx: &ExtCtxt<'ctx>, + dcx: &'ctx DiagCtxt, ident: Ident, interp: &'interp FxHashMap, ) -> PResult<'ctx, &'rslt NamedMatch> @@ -643,12 +641,12 @@ where { let span = ident.span; let key = MacroRulesNormalizedIdent::new(ident); - interp.get(&key).ok_or_else(|| cx.dcx().create_err(MetaVarExprUnrecognizedVar { span, key })) + interp.get(&key).ok_or_else(|| dcx.create_err(MetaVarExprUnrecognizedVar { span, key })) } /// Used by meta-variable expressions when an user input is out of the actual declared bounds. For /// example, index(999999) in an repetition of only three elements. -fn out_of_bounds_err<'a>(cx: &ExtCtxt<'a>, max: usize, span: Span, ty: &str) -> Diag<'a> { +fn out_of_bounds_err<'a>(dcx: &'a DiagCtxt, max: usize, span: Span, ty: &str) -> Diag<'a> { let msg = if max == 0 { format!( "meta-variable expression `{ty}` with depth parameter \ @@ -660,11 +658,11 @@ fn out_of_bounds_err<'a>(cx: &ExtCtxt<'a>, max: usize, span: Span, ty: &str) -> must be less than {max}" ) }; - cx.dcx().struct_span_err(span, msg) + dcx.struct_span_err(span, msg) } fn transcribe_metavar_expr<'a>( - cx: &ExtCtxt<'a>, + dcx: &'a DiagCtxt, expr: &MetaVarExpr, interp: &FxHashMap, marker: &mut Marker, @@ -679,8 +677,8 @@ fn transcribe_metavar_expr<'a>( }; match *expr { MetaVarExpr::Count(original_ident, depth) => { - let matched = matched_from_ident(cx, original_ident, interp)?; - let count = count_repetitions(cx, depth, matched, repeats, sp)?; + let matched = matched_from_ident(dcx, original_ident, interp)?; + let count = count_repetitions(dcx, depth, matched, repeats, sp)?; let tt = TokenTree::token_alone( TokenKind::lit(token::Integer, sym::integer(count), None), visited_span(), @@ -689,7 +687,7 @@ fn transcribe_metavar_expr<'a>( } MetaVarExpr::Ignore(original_ident) => { // Used to ensure that `original_ident` is present in the LHS - let _ = matched_from_ident(cx, original_ident, interp)?; + let _ = matched_from_ident(dcx, original_ident, interp)?; } MetaVarExpr::Index(depth) => match repeats.iter().nth_back(depth) { Some((index, _)) => { @@ -698,7 +696,7 @@ fn transcribe_metavar_expr<'a>( visited_span(), )); } - None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "index")), + None => return Err(out_of_bounds_err(dcx, repeats.len(), sp.entire(), "index")), }, MetaVarExpr::Len(depth) => match repeats.iter().nth_back(depth) { Some((_, length)) => { @@ -707,7 +705,7 @@ fn transcribe_metavar_expr<'a>( visited_span(), )); } - None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "len")), + None => return Err(out_of_bounds_err(dcx, repeats.len(), sp.entire(), "len")), }, } Ok(()) 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 39ced1c803f7..8928711253cd 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -449,7 +449,7 @@ impl<'tcx> TypeFolder> for RemapLateBound<'_, 'tcx> { pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( tcx: TyCtxt<'tcx>, impl_m_def_id: LocalDefId, -) -> Result<&'tcx DefIdMap>>, ErrorGuaranteed> { +) -> Result<&'tcx DefIdMap>>, ErrorGuaranteed> { let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap(); let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap(); let impl_trait_ref = diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 40cd65b899e2..75e35e7bf50c 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1277,7 +1277,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { } #[instrument(level = "debug", skip(tcx))] -fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder> { +fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFnSig<'_>> { use rustc_hir::Node::*; use rustc_hir::*; diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index dd1d209389dc..50c93e9f1d7e 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -82,14 +82,14 @@ fn opaque_type_bounds<'tcx>( pub(super) fn explicit_item_bounds( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> { +) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> { explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::All) } pub(super) fn explicit_item_super_predicates( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> { +) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> { explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::SelfOnly) } @@ -97,7 +97,7 @@ pub(super) fn explicit_item_bounds_with_filter( tcx: TyCtxt<'_>, def_id: LocalDefId, filter: PredicateFilter, -) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> { +) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> { match tcx.opt_rpitit_info(def_id.to_def_id()) { // RPITIT's bounds are the same as opaque type bounds, but with // a projection self type. @@ -166,7 +166,7 @@ pub(super) fn explicit_item_bounds_with_filter( ty::EarlyBinder::bind(bounds) } -pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder> { +pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<'_, ty::Clauses<'_>> { tcx.explicit_item_bounds(def_id).map_bound(|bounds| { tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound))) }) @@ -175,7 +175,7 @@ pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder, def_id: DefId, -) -> ty::EarlyBinder> { +) -> ty::EarlyBinder<'_, ty::Clauses<'_>> { tcx.explicit_item_super_predicates(def_id).map_bound(|bounds| { tcx.mk_clauses_from_iter( util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)).filter_only_self(), @@ -186,7 +186,7 @@ pub(super) fn item_super_predicates( pub(super) fn item_non_self_assumptions( tcx: TyCtxt<'_>, def_id: DefId, -) -> ty::EarlyBinder> { +) -> ty::EarlyBinder<'_, ty::Clauses<'_>> { let all_bounds: FxIndexSet<_> = tcx.item_bounds(def_id).skip_binder().iter().collect(); let own_bounds: FxIndexSet<_> = tcx.item_super_predicates(def_id).skip_binder().iter().collect(); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 1475e53c47c2..ed942cc50bb4 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -309,7 +309,7 @@ fn get_path_containing_arg_in_pat<'hir>( arg_path } -pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder> { +pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, Ty<'_>> { use rustc_hir::*; use rustc_middle::ty::Ty; @@ -512,7 +512,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder, def_id: DefId, -) -> Result>, CyclePlaceholder> { +) -> Result>, CyclePlaceholder> { if let Some(def_id) = def_id.as_local() { use rustc_hir::*; diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index 1de7a0f7bc73..bbfadbb5c308 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -6,7 +6,7 @@ use super::utils::*; #[derive(Debug)] pub struct ExplicitPredicatesMap<'tcx> { - map: FxIndexMap>>, + map: FxIndexMap>>, } impl<'tcx> ExplicitPredicatesMap<'tcx> { @@ -18,7 +18,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { &mut self, tcx: TyCtxt<'tcx>, def_id: DefId, - ) -> &ty::EarlyBinder> { + ) -> &ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>> { self.map.entry(def_id).or_insert_with(|| { let predicates = if def_id.is_local() { tcx.explicit_predicates_of(def_id) diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index e6c582667ba5..af08f50f6559 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -15,7 +15,7 @@ use super::utils::*; /// now be filled with inferred predicates. pub(super) fn infer_predicates( tcx: TyCtxt<'_>, -) -> FxIndexMap>> { +) -> FxIndexMap>> { debug!("infer_predicates"); let mut explicit_map = ExplicitPredicatesMap::new(); @@ -101,7 +101,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, - global_inferred_outlives: &FxIndexMap>>, + global_inferred_outlives: &FxIndexMap>>, required_predicates: &mut RequiredPredicates<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>, ) { @@ -322,7 +322,7 @@ fn check_inferred_predicates<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, args: ty::GenericArgsRef<'tcx>, - global_inferred_outlives: &FxIndexMap>>, + global_inferred_outlives: &FxIndexMap>>, required_predicates: &mut RequiredPredicates<'tcx>, ) { // Load the current set of inferred and explicit predicates from `global_inferred_outlives` diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index b3e93748a166..87ee5f536280 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -270,7 +270,7 @@ fn impl_trait_ref_has_enough_non_local_candidates<'tcx>( tcx: TyCtxt<'tcx>, infer_span: Span, trait_def_id: DefId, - binder: EarlyBinder>, + binder: EarlyBinder<'tcx, TraitRef<'tcx>>, mut did_has_local_parent: impl FnMut(DefId) -> bool, ) -> bool { let infcx = tcx diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 42e12a88fa53..13867319e5cd 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3757,7 +3757,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust,compile_fail + /// ```rust,edition2018,compile_fail /// #![deny(rust_2021_incompatible_or_patterns)] /// /// macro_rules! match_any { @@ -3797,7 +3797,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust,compile_fail + /// ```rust,edition2018,compile_fail /// #![deny(rust_2021_prelude_collisions)] /// /// trait Foo { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 695525e755de..19bb943e6bcc 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1074,7 +1074,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self, index: DefIndex, tcx: TyCtxt<'tcx>, - ) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> { + ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> { let lazy = self.root.tables.explicit_item_bounds.get(self, index); let output = if lazy.is_default() { &mut [] @@ -1088,7 +1088,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self, index: DefIndex, tcx: TyCtxt<'tcx>, - ) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> { + ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> { let lazy = self.root.tables.explicit_item_super_predicates.get(self, index); let output = if lazy.is_default() { &mut [] diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 825034cf96a9..c2cf5b6b7125 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -418,19 +418,19 @@ define_tables! { // As an optimization, we only store this for trait aliases, // since it's identical to super_predicates_of for traits. implied_predicates_of: Table>>, - type_of: Table>>>, + type_of: Table>>>, variances_of: Table>, - fn_sig: Table>>>, + fn_sig: Table>>>, codegen_fn_attrs: Table>, impl_trait_header: Table>>, - const_param_default: Table>>>, + const_param_default: Table>>>, object_lifetime_default: Table>, optimized_mir: Table>>, mir_for_ctfe: Table>>, closure_saved_names_of_captured_variables: Table>>, mir_coroutine_witnesses: Table>>, promoted_mir: Table>>>, - thir_abstract_const: Table>>>, + thir_abstract_const: Table>>>, impl_parent: Table, constness: Table, defaultness: Table, @@ -459,7 +459,7 @@ define_tables! { macro_definition: Table>, proc_macro: Table, deduced_param_attrs: Table>, - trait_impl_trait_tys: Table>>>>, + trait_impl_trait_tys: Table>>>>, doc_link_resolutions: Table>, doc_link_traits_in_scope: Table>, assumed_wf_types_for_rpitit: Table, Span)>>, diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index b0e72eaf5a4c..bf6ab8000645 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -108,7 +108,7 @@ macro_rules! arena_types { [decode] trait_impl_trait_tys: rustc_data_structures::unord::UnordMap< rustc_hir::def_id::DefId, - rustc_middle::ty::EarlyBinder> + rustc_middle::ty::EarlyBinder<'tcx, rustc_middle::ty::Ty<'tcx>> >, [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>, [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<'tcx>, diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 34748afa863d..d39422b2b04d 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -121,7 +121,7 @@ impl<'tcx> TyCtxt<'tcx> { LocalModDefId::new_unchecked(id) } - pub fn impl_subject(self, def_id: DefId) -> EarlyBinder> { + pub fn impl_subject(self, def_id: DefId) -> EarlyBinder<'tcx, ImplSubject<'tcx>> { match self.impl_trait_ref(def_id) { Some(t) => t.map_bound(ImplSubject::Trait), None => self.type_of(def_id).map_bound(ImplSubject::Inherent), diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index d025dc360a24..e107c2c12bd6 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -220,7 +220,10 @@ pub enum Const<'tcx> { } impl<'tcx> Const<'tcx> { - pub fn identity_unevaluated(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::EarlyBinder> { + pub fn identity_unevaluated( + tcx: TyCtxt<'tcx>, + def_id: DefId, + ) -> ty::EarlyBinder<'tcx, Const<'tcx>> { ty::EarlyBinder::bind(Const::Unevaluated( UnevaluatedConst { def: def_id, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 2b2b9392a709..02e5174a715d 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -624,7 +624,7 @@ impl<'tcx> Body<'tcx> { /// Returns the return type; it always return first element from `local_decls` array. #[inline] - pub fn bound_return_ty(&self) -> ty::EarlyBinder> { + pub fn bound_return_ty(&self) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { ty::EarlyBinder::bind(self.local_decls[RETURN_PLACE].ty) } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 2b28496faec7..2d4852114332 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1008,8 +1008,8 @@ pub type AssertMessage<'tcx> = AssertKind>; /// element: /// /// - [`Downcast`](ProjectionElem::Downcast): This projection sets the place's variant index to the -/// given one, and makes no other changes. A `Downcast` projection on a place with its variant -/// index already set is not well-formed. +/// given one, and makes no other changes. A `Downcast` projection must always be followed +/// immediately by a `Field` projection. /// - [`Field`](ProjectionElem::Field): `Field` projections take their parent place and create a /// place referring to one of the fields of the type. The resulting address is the parent /// address, plus the offset of the field. The type becomes the type of the field. If the parent diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 320d49ea6467..1e36f034cc22 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -114,9 +114,11 @@ impl EraseType for Result { type Result = [u8; size_of::>()]; } -impl EraseType for Result>>, rustc_errors::ErrorGuaranteed> { +impl EraseType + for Result>>, rustc_errors::ErrorGuaranteed> +{ type Result = [u8; size_of::< - Result>>, rustc_errors::ErrorGuaranteed>, + Result>>, rustc_errors::ErrorGuaranteed>, >()]; } @@ -165,8 +167,8 @@ impl EraseType for Result<&'_ ty::List>, ty::util::AlwaysRequiresDrop> { [u8; size_of::>, ty::util::AlwaysRequiresDrop>>()]; } -impl EraseType for Result>, CyclePlaceholder> { - type Result = [u8; size_of::>, CyclePlaceholder>>()]; +impl EraseType for Result>, CyclePlaceholder> { + type Result = [u8; size_of::>, CyclePlaceholder>>()]; } impl EraseType for Option<&'_ T> { @@ -185,15 +187,15 @@ impl EraseType for Option> { type Result = [u8; size_of::>>()]; } -impl EraseType for Option>> { - type Result = [u8; size_of::>>>()]; +impl EraseType for Option>> { + type Result = [u8; size_of::>>>()]; } impl EraseType for rustc_hir::MaybeOwner<'_> { type Result = [u8; size_of::>()]; } -impl EraseType for ty::EarlyBinder { +impl EraseType for ty::EarlyBinder<'_, T> { type Result = T::Result; } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 8ca7a465c2a8..6ad4b7c40fb2 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -209,7 +209,7 @@ rustc_queries! { /// Given the def_id of a const-generic parameter, computes the associated default const /// parameter. e.g. `fn example` called on `N` would return `3`. - query const_param_default(param: DefId) -> ty::EarlyBinder> { + query const_param_default(param: DefId) -> ty::EarlyBinder<'tcx, ty::Const<'tcx>> { desc { |tcx| "computing const default for a given parameter `{}`", tcx.def_path_str(param) } cache_on_disk_if { param.is_local() } separate_provide_extern @@ -219,7 +219,7 @@ rustc_queries! { /// to an alias, it will "skip" this alias to return the aliased type. /// /// [`DefId`]: rustc_hir::def_id::DefId - query type_of(key: DefId) -> ty::EarlyBinder> { + query type_of(key: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { desc { |tcx| "{action} `{path}`", action = { @@ -240,7 +240,7 @@ rustc_queries! { /// Specialized instance of `type_of` that detects cycles that are due to /// revealing opaque because of an auto trait bound. Unless `CyclePlaceholder` needs /// to be handled separately, call `type_of` instead. - query type_of_opaque(key: DefId) -> Result>, CyclePlaceholder> { + query type_of_opaque(key: DefId) -> Result>, CyclePlaceholder> { desc { |tcx| "computing type of opaque `{path}`", path = tcx.def_path_str(key), @@ -257,7 +257,7 @@ rustc_queries! { } query collect_return_position_impl_trait_in_trait_tys(key: DefId) - -> Result<&'tcx DefIdMap>>, ErrorGuaranteed> + -> Result<&'tcx DefIdMap>>, ErrorGuaranteed> { desc { "comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process" } cache_on_disk_if { key.is_local() } @@ -363,7 +363,7 @@ rustc_queries! { /// `key` is the `DefId` of the associated type or opaque type. /// /// Bounds from the parent (e.g. with nested impl trait) are not included. - query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> { + query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern @@ -373,7 +373,7 @@ rustc_queries! { /// share the `Self` type of the item. These are a subset of the bounds /// that may explicitly be used for things like closure signature /// deduction. - query explicit_item_super_predicates(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> { + query explicit_item_super_predicates(key: DefId) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern @@ -399,15 +399,15 @@ rustc_queries! { /// ``` /// /// Bounds from the parent (e.g. with nested impl trait) are not included. - query item_bounds(key: DefId) -> ty::EarlyBinder> { + query item_bounds(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> { desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) } } - query item_super_predicates(key: DefId) -> ty::EarlyBinder> { + query item_super_predicates(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> { desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) } } - query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder> { + query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> { desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) } } @@ -504,7 +504,7 @@ rustc_queries! { /// Try to build an abstract representation of the given constant. query thir_abstract_const( key: DefId - ) -> Result>>, ErrorGuaranteed> { + ) -> Result>>, ErrorGuaranteed> { desc { |tcx| "building an abstract representation for `{}`", tcx.def_path_str(key), } @@ -704,7 +704,7 @@ rustc_queries! { separate_provide_extern } - query adt_sized_constraint(key: DefId) -> Option>> { + query adt_sized_constraint(key: DefId) -> Option>> { desc { |tcx| "computing the `Sized` constraint for `{}`", tcx.def_path_str(key) } } @@ -849,7 +849,7 @@ rustc_queries! { query self_ty_of_trait_impl_enabling_order_dep_trait_object_hack( key: DefId - ) -> Option>> { + ) -> Option>> { desc { |tcx| "computing self type wrt issue #33140 `{}`", tcx.def_path_str(key) } } @@ -888,7 +888,7 @@ rustc_queries! { } /// Computes the signature of the function. - query fn_sig(key: DefId) -> ty::EarlyBinder> { + query fn_sig(key: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> { desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 941911c22309..ccd0c7cb10c4 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -752,7 +752,7 @@ impl<'a, 'tcx> Decodable> for &'tcx UnordSet } impl<'a, 'tcx> Decodable> - for &'tcx UnordMap>> + for &'tcx UnordMap>> { #[inline] fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index dc46b470b6f4..7fb5e9aadae7 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -30,7 +30,8 @@ impl From for NotConstEvaluatable { TrivialTypeTraversalImpls! { NotConstEvaluatable } -pub type BoundAbstractConst<'tcx> = Result>>, ErrorGuaranteed>; +pub type BoundAbstractConst<'tcx> = + Result>>, ErrorGuaranteed>; impl<'tcx> TyCtxt<'tcx> { pub fn expand_abstract_consts>>(self, ac: T) -> T { diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 48193754077d..8e946bc8b314 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -579,7 +579,7 @@ impl<'tcx> AdtDef<'tcx> { /// Returns a type such that `Self: Sized` if and only if that type is `Sized`, /// or `None` if the type is always sized. - pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option>> { + pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option>> { if self.is_struct() { tcx.adt_sized_constraint(self.did()) } else { None } } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 40a0dbeb2c22..6416bbbe889c 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -184,6 +184,15 @@ impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> { Const::new_var(tcx, vid, ty) } + fn new_bound( + interner: TyCtxt<'tcx>, + debruijn: ty::DebruijnIndex, + var: ty::BoundVar, + ty: Ty<'tcx>, + ) -> Self { + Const::new_bound(interner, debruijn, var, ty) + } + fn new_anon_bound( tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, @@ -486,7 +495,10 @@ impl<'tcx> Const<'tcx> { } } -pub fn const_param_default(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder> { +pub fn const_param_default<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> ty::EarlyBinder<'tcx, Const<'tcx>> { let default_def_id = match tcx.hir_node_by_def_id(def_id) { hir::Node::GenericParam(hir::GenericParam { kind: hir::GenericParamKind::Const { default: Some(ac), .. }, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e618323c810d..c09cb95de883 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -149,8 +149,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.generics_of(def_id) } - fn type_of_instantiated(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Ty<'tcx> { - self.type_of(def_id).instantiate(self, args) + fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { + self.type_of(def_id) } fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind { @@ -679,7 +679,7 @@ impl<'tcx> TyCtxt<'tcx> { /// In order to break cycles involving `AnonConst`, we need to set the expected type by side /// effect. However, we do not want this as a general capability, so this interface restricts /// to the only allowed case. - pub fn feed_anon_const_type(self, key: LocalDefId, value: ty::EarlyBinder>) { + pub fn feed_anon_const_type(self, key: LocalDefId, value: ty::EarlyBinder<'tcx, Ty<'tcx>>) { debug_assert_eq!(self.def_kind(key), DefKind::AnonConst); TyCtxtFeed { tcx: self, key }.type_of(value) } @@ -2741,7 +2741,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn impl_trait_ref( self, def_id: impl IntoQueryParam, - ) -> Option>> { + ) -> Option>> { Some(self.impl_trait_header(def_id)?.trait_ref) } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index d432aeada2c8..b5b36cbd1ba1 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -3,7 +3,9 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; use tracing::{debug, instrument}; -pub use rustc_type_ir::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; +pub use rustc_type_ir::fold::{ + shift_region, shift_vars, FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, +}; /////////////////////////////////////////////////////////////////////////// // Some sample folders @@ -412,103 +414,3 @@ impl<'tcx> TyCtxt<'tcx> { Binder::bind_with_vars(inner, bound_vars) } } - -/////////////////////////////////////////////////////////////////////////// -// Shifter -// -// Shifts the De Bruijn indices on all escaping bound vars by a -// fixed amount. Useful in instantiation or when otherwise introducing -// a binding level that is not intended to capture the existing bound -// vars. See comment on `shift_vars_through_binders` method in -// `rustc_middle/src/ty/generic_args.rs` for more details. - -struct Shifter<'tcx> { - tcx: TyCtxt<'tcx>, - current_index: ty::DebruijnIndex, - amount: u32, -} - -impl<'tcx> Shifter<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, amount: u32) -> Self { - Shifter { tcx, current_index: ty::INNERMOST, amount } - } -} - -impl<'tcx> TypeFolder> for Shifter<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_binder>>( - &mut self, - t: ty::Binder<'tcx, T>, - ) -> ty::Binder<'tcx, T> { - self.current_index.shift_in(1); - let t = t.super_fold_with(self); - self.current_index.shift_out(1); - t - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { - ty::ReBound(debruijn, br) if debruijn >= self.current_index => { - let debruijn = debruijn.shifted_in(self.amount); - ty::Region::new_bound(self.tcx, debruijn, br) - } - _ => r, - } - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match *ty.kind() { - ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { - let debruijn = debruijn.shifted_in(self.amount); - Ty::new_bound(self.tcx, debruijn, bound_ty) - } - - _ if ty.has_vars_bound_at_or_above(self.current_index) => ty.super_fold_with(self), - _ => ty, - } - } - - fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - if let ty::ConstKind::Bound(debruijn, bound_ct) = ct.kind() - && debruijn >= self.current_index - { - let debruijn = debruijn.shifted_in(self.amount); - ty::Const::new_bound(self.tcx, debruijn, bound_ct, ct.ty()) - } else { - ct.super_fold_with(self) - } - } - - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { - if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } - } -} - -pub fn shift_region<'tcx>( - tcx: TyCtxt<'tcx>, - region: ty::Region<'tcx>, - amount: u32, -) -> ty::Region<'tcx> { - match *region { - ty::ReBound(debruijn, br) if amount > 0 => { - ty::Region::new_bound(tcx, debruijn.shifted_in(amount), br) - } - _ => region, - } -} - -pub fn shift_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: T, amount: u32) -> T -where - T: TypeFoldable>, -{ - debug!("shift_vars(value={:?}, amount={})", value, amount); - - if amount == 0 || !value.has_escaping_bound_vars() { - return value; - } - - value.fold_with(&mut Shifter::new(tcx, amount)) -} diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index c7b15c64b086..7a516b9f2c80 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -1,10 +1,10 @@ // Generic arguments. use crate::ty::codec::{TyDecoder, TyEncoder}; -use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; +use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; use crate::ty::sty::{ClosureArgs, CoroutineArgs, CoroutineClosureArgs, InlineConstArgs}; -use crate::ty::visit::{TypeVisitable, TypeVisitableExt, TypeVisitor}; -use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; +use crate::ty::visit::{TypeVisitable, TypeVisitor}; +use crate::ty::{self, Lift, List, Ty, TyCtxt}; use rustc_ast_ir::visit::VisitorResult; use rustc_ast_ir::walk_visitable_list; @@ -12,19 +12,15 @@ use rustc_data_structures::intern::Interned; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_hir::def_id::DefId; use rustc_macros::extension; -use rustc_macros::{ - Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, -}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_serialize::{Decodable, Encodable}; use rustc_type_ir::WithCachedTypeInfo; use smallvec::SmallVec; -use tracing::debug; use core::intrinsics; use std::marker::PhantomData; use std::mem; use std::num::NonZero; -use std::ops::Deref; use std::ptr::NonNull; pub type GenericArgKind<'tcx> = rustc_type_ir::GenericArgKind>; @@ -576,490 +572,6 @@ impl<'tcx, T: TypeVisitable>> TypeVisitable> for &'tcx } } -/// Similar to [`super::Binder`] except that it tracks early bound generics, i.e. `struct Foo(T)` -/// needs `T` instantiated immediately. This type primarily exists to avoid forgetting to call -/// `instantiate`. -/// -/// If you don't have anything to `instantiate`, you may be looking for -/// [`instantiate_identity`](EarlyBinder::instantiate_identity) or [`skip_binder`](EarlyBinder::skip_binder). -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(Encodable, Decodable, HashStable)] -pub struct EarlyBinder { - value: T, -} - -/// For early binders, you should first call `instantiate` before using any visitors. -impl<'tcx, T> !TypeFoldable> for ty::EarlyBinder {} -impl<'tcx, T> !TypeVisitable> for ty::EarlyBinder {} - -impl EarlyBinder { - pub fn bind(value: T) -> EarlyBinder { - EarlyBinder { value } - } - - pub fn as_ref(&self) -> EarlyBinder<&T> { - EarlyBinder { value: &self.value } - } - - pub fn map_bound_ref(&self, f: F) -> EarlyBinder - where - F: FnOnce(&T) -> U, - { - self.as_ref().map_bound(f) - } - - pub fn map_bound(self, f: F) -> EarlyBinder - where - F: FnOnce(T) -> U, - { - let value = f(self.value); - EarlyBinder { value } - } - - pub fn try_map_bound(self, f: F) -> Result, E> - where - F: FnOnce(T) -> Result, - { - let value = f(self.value)?; - Ok(EarlyBinder { value }) - } - - pub fn rebind(&self, value: U) -> EarlyBinder { - EarlyBinder { value } - } - - /// Skips the binder and returns the "bound" value. - /// This can be used to extract data that does not depend on generic parameters - /// (e.g., getting the `DefId` of the inner value or getting the number of - /// arguments of an `FnSig`). Otherwise, consider using - /// [`instantiate_identity`](EarlyBinder::instantiate_identity). - /// - /// To skip the binder on `x: &EarlyBinder` to obtain `&T`, leverage - /// [`EarlyBinder::as_ref`](EarlyBinder::as_ref): `x.as_ref().skip_binder()`. - /// - /// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is - /// the analogous operation on [`super::Binder`]. - pub fn skip_binder(self) -> T { - self.value - } -} - -impl EarlyBinder> { - pub fn transpose(self) -> Option> { - self.value.map(|value| EarlyBinder { value }) - } -} - -impl<'tcx, 's, I: IntoIterator> EarlyBinder -where - I::Item: TypeFoldable>, -{ - pub fn iter_instantiated( - self, - tcx: TyCtxt<'tcx>, - args: &'s [GenericArg<'tcx>], - ) -> IterInstantiated<'s, 'tcx, I> { - IterInstantiated { it: self.value.into_iter(), tcx, args } - } - - /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity), - /// but on an iterator of `TypeFoldable` values. - pub fn instantiate_identity_iter(self) -> I::IntoIter { - self.value.into_iter() - } -} - -pub struct IterInstantiated<'s, 'tcx, I: IntoIterator> { - it: I::IntoIter, - tcx: TyCtxt<'tcx>, - args: &'s [GenericArg<'tcx>], -} - -impl<'tcx, I: IntoIterator> Iterator for IterInstantiated<'_, 'tcx, I> -where - I::Item: TypeFoldable>, -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - Some(EarlyBinder { value: self.it.next()? }.instantiate(self.tcx, self.args)) - } - - fn size_hint(&self) -> (usize, Option) { - self.it.size_hint() - } -} - -impl<'tcx, I: IntoIterator> DoubleEndedIterator for IterInstantiated<'_, 'tcx, I> -where - I::IntoIter: DoubleEndedIterator, - I::Item: TypeFoldable>, -{ - fn next_back(&mut self) -> Option { - Some(EarlyBinder { value: self.it.next_back()? }.instantiate(self.tcx, self.args)) - } -} - -impl<'tcx, I: IntoIterator> ExactSizeIterator for IterInstantiated<'_, 'tcx, I> -where - I::IntoIter: ExactSizeIterator, - I::Item: TypeFoldable>, -{ -} - -impl<'tcx, 's, I: IntoIterator> EarlyBinder -where - I::Item: Deref, - ::Target: Copy + TypeFoldable>, -{ - pub fn iter_instantiated_copied( - self, - tcx: TyCtxt<'tcx>, - args: &'s [GenericArg<'tcx>], - ) -> IterInstantiatedCopied<'s, 'tcx, I> { - IterInstantiatedCopied { it: self.value.into_iter(), tcx, args } - } - - /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity), - /// but on an iterator of values that deref to a `TypeFoldable`. - pub fn instantiate_identity_iter_copied( - self, - ) -> impl Iterator::Target> { - self.value.into_iter().map(|v| *v) - } -} - -pub struct IterInstantiatedCopied<'a, 'tcx, I: IntoIterator> { - it: I::IntoIter, - tcx: TyCtxt<'tcx>, - args: &'a [GenericArg<'tcx>], -} - -impl<'tcx, I: IntoIterator> Iterator for IterInstantiatedCopied<'_, 'tcx, I> -where - I::Item: Deref, - ::Target: Copy + TypeFoldable>, -{ - type Item = ::Target; - - fn next(&mut self) -> Option { - self.it.next().map(|value| EarlyBinder { value: *value }.instantiate(self.tcx, self.args)) - } - - fn size_hint(&self) -> (usize, Option) { - self.it.size_hint() - } -} - -impl<'tcx, I: IntoIterator> DoubleEndedIterator for IterInstantiatedCopied<'_, 'tcx, I> -where - I::IntoIter: DoubleEndedIterator, - I::Item: Deref, - ::Target: Copy + TypeFoldable>, -{ - fn next_back(&mut self) -> Option { - self.it - .next_back() - .map(|value| EarlyBinder { value: *value }.instantiate(self.tcx, self.args)) - } -} - -impl<'tcx, I: IntoIterator> ExactSizeIterator for IterInstantiatedCopied<'_, 'tcx, I> -where - I::IntoIter: ExactSizeIterator, - I::Item: Deref, - ::Target: Copy + TypeFoldable>, -{ -} - -pub struct EarlyBinderIter { - t: T, -} - -impl EarlyBinder { - pub fn transpose_iter(self) -> EarlyBinderIter { - EarlyBinderIter { t: self.value.into_iter() } - } -} - -impl Iterator for EarlyBinderIter { - type Item = EarlyBinder; - - fn next(&mut self) -> Option { - self.t.next().map(|value| EarlyBinder { value }) - } - - fn size_hint(&self) -> (usize, Option) { - self.t.size_hint() - } -} - -impl<'tcx, T: TypeFoldable>> ty::EarlyBinder { - pub fn instantiate(self, tcx: TyCtxt<'tcx>, args: &[GenericArg<'tcx>]) -> T { - let mut folder = ArgFolder { tcx, args, binders_passed: 0 }; - self.value.fold_with(&mut folder) - } - - /// Makes the identity replacement `T0 => T0, ..., TN => TN`. - /// Conceptually, this converts universally bound variables into placeholders - /// when inside of a given item. - /// - /// For example, consider `for fn foo(){ .. }`: - /// - Outside of `foo`, `T` is bound (represented by the presence of `EarlyBinder`). - /// - Inside of the body of `foo`, we treat `T` as a placeholder by calling - /// `instantiate_identity` to discharge the `EarlyBinder`. - pub fn instantiate_identity(self) -> T { - self.value - } - - /// Returns the inner value, but only if it contains no bound vars. - pub fn no_bound_vars(self) -> Option { - if !self.value.has_param() { Some(self.value) } else { None } - } -} - -/////////////////////////////////////////////////////////////////////////// -// The actual instantiation engine itself is a type folder. - -struct ArgFolder<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - args: &'a [GenericArg<'tcx>], - - /// Number of region binders we have passed through while doing the instantiation - binders_passed: u32, -} - -impl<'a, 'tcx> TypeFolder> for ArgFolder<'a, 'tcx> { - #[inline] - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_binder>>( - &mut self, - t: ty::Binder<'tcx, T>, - ) -> ty::Binder<'tcx, T> { - self.binders_passed += 1; - let t = t.super_fold_with(self); - self.binders_passed -= 1; - t - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - #[cold] - #[inline(never)] - fn region_param_out_of_range(data: ty::EarlyParamRegion, args: &[GenericArg<'_>]) -> ! { - bug!( - "Region parameter out of range when instantiating in region {} (index={}, args = {:?})", - data.name, - data.index, - args, - ) - } - - #[cold] - #[inline(never)] - fn region_param_invalid(data: ty::EarlyParamRegion, other: GenericArgKind<'_>) -> ! { - bug!( - "Unexpected parameter {:?} when instantiating in region {} (index={})", - other, - data.name, - data.index - ) - } - - // Note: This routine only handles regions that are bound on - // type declarations and other outer declarations, not those - // bound in *fn types*. Region instantiation of the bound - // regions that appear in a function signature is done using - // the specialized routine `ty::replace_late_regions()`. - match *r { - ty::ReEarlyParam(data) => { - let rk = self.args.get(data.index as usize).map(|k| k.unpack()); - match rk { - Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt), - Some(other) => region_param_invalid(data, other), - None => region_param_out_of_range(data, self.args), - } - } - ty::ReBound(..) - | ty::ReLateParam(_) - | ty::ReStatic - | ty::RePlaceholder(_) - | ty::ReErased - | ty::ReError(_) => r, - ty::ReVar(_) => bug!("unexpected region: {r:?}"), - } - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.has_param() { - return t; - } - - match *t.kind() { - ty::Param(p) => self.ty_for_param(p, t), - _ => t.super_fold_with(self), - } - } - - fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { - if let ty::ConstKind::Param(p) = c.kind() { - self.const_for_param(p, c) - } else { - c.super_fold_with(self) - } - } -} - -impl<'a, 'tcx> ArgFolder<'a, 'tcx> { - fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> { - // Look up the type in the args. It really should be in there. - let opt_ty = self.args.get(p.index as usize).map(|k| k.unpack()); - let ty = match opt_ty { - Some(GenericArgKind::Type(ty)) => ty, - Some(kind) => self.type_param_expected(p, source_ty, kind), - None => self.type_param_out_of_range(p, source_ty), - }; - - self.shift_vars_through_binders(ty) - } - - #[cold] - #[inline(never)] - fn type_param_expected(&self, p: ty::ParamTy, ty: Ty<'tcx>, kind: GenericArgKind<'tcx>) -> ! { - bug!( - "expected type for `{:?}` ({:?}/{}) but found {:?} when instantiating, args={:?}", - p, - ty, - p.index, - kind, - self.args, - ) - } - - #[cold] - #[inline(never)] - fn type_param_out_of_range(&self, p: ty::ParamTy, ty: Ty<'tcx>) -> ! { - bug!( - "type parameter `{:?}` ({:?}/{}) out of range when instantiating, args={:?}", - p, - ty, - p.index, - self.args, - ) - } - - fn const_for_param(&self, p: ParamConst, source_ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - // Look up the const in the args. It really should be in there. - let opt_ct = self.args.get(p.index as usize).map(|k| k.unpack()); - let ct = match opt_ct { - Some(GenericArgKind::Const(ct)) => ct, - Some(kind) => self.const_param_expected(p, source_ct, kind), - None => self.const_param_out_of_range(p, source_ct), - }; - - self.shift_vars_through_binders(ct) - } - - #[cold] - #[inline(never)] - fn const_param_expected( - &self, - p: ty::ParamConst, - ct: ty::Const<'tcx>, - kind: GenericArgKind<'tcx>, - ) -> ! { - bug!( - "expected const for `{:?}` ({:?}/{}) but found {:?} when instantiating args={:?}", - p, - ct, - p.index, - kind, - self.args, - ) - } - - #[cold] - #[inline(never)] - fn const_param_out_of_range(&self, p: ty::ParamConst, ct: ty::Const<'tcx>) -> ! { - bug!( - "const parameter `{:?}` ({:?}/{}) out of range when instantiating args={:?}", - p, - ct, - p.index, - self.args, - ) - } - - /// It is sometimes necessary to adjust the De Bruijn indices during instantiation. This occurs - /// when we are instantating a type with escaping bound vars into a context where we have - /// passed through binders. That's quite a mouthful. Let's see an example: - /// - /// ``` - /// type Func = fn(A); - /// type MetaFunc = for<'a> fn(Func<&'a i32>); - /// ``` - /// - /// The type `MetaFunc`, when fully expanded, will be - /// ```ignore (illustrative) - /// for<'a> fn(fn(&'a i32)) - /// // ^~ ^~ ^~~ - /// // | | | - /// // | | DebruijnIndex of 2 - /// // Binders - /// ``` - /// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the - /// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip - /// over the inner binder (remember that we count De Bruijn indices from 1). However, in the - /// definition of `MetaFunc`, the binder is not visible, so the type `&'a i32` will have a - /// De Bruijn index of 1. It's only during the instantiation that we can see we must increase the - /// depth by 1 to account for the binder that we passed through. - /// - /// As a second example, consider this twist: - /// - /// ``` - /// type FuncTuple = (A,fn(A)); - /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a i32>); - /// ``` - /// - /// Here the final type will be: - /// ```ignore (illustrative) - /// for<'a> fn((&'a i32, fn(&'a i32))) - /// // ^~~ ^~~ - /// // | | - /// // DebruijnIndex of 1 | - /// // DebruijnIndex of 2 - /// ``` - /// As indicated in the diagram, here the same type `&'a i32` is instantiated once, but in the - /// first case we do not increase the De Bruijn index and in the second case we do. The reason - /// is that only in the second case have we passed through a fn binder. - fn shift_vars_through_binders>>(&self, val: T) -> T { - debug!( - "shift_vars(val={:?}, binders_passed={:?}, has_escaping_bound_vars={:?})", - val, - self.binders_passed, - val.has_escaping_bound_vars() - ); - - if self.binders_passed == 0 || !val.has_escaping_bound_vars() { - return val; - } - - let result = ty::fold::shift_vars(TypeFolder::interner(self), val, self.binders_passed); - debug!("shift_vars: shifted result = {:?}", result); - - result - } - - fn shift_region_through_binders(&self, region: ty::Region<'tcx>) -> ty::Region<'tcx> { - if self.binders_passed == 0 || !region.has_escaping_bound_vars() { - return region; - } - ty::fold::shift_region(self.tcx, region, self.binders_passed) - } -} - /// Stores the user-given args to reach some fully qualified path /// (e.g., `::Item` or `::Item`). #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 69a86bda43ba..89ba8cd2ad4c 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -88,7 +88,7 @@ impl GenericParamDef { pub fn default_value<'tcx>( &self, tcx: TyCtxt<'tcx>, - ) -> Option>> { + ) -> Option>> { match self.kind { GenericParamDefKind::Type { has_default, .. } if has_default => { Some(tcx.type_of(self.def_id).map_bound(|t| t.into())) diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 7da7f69a9543..a887047f62f2 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -764,7 +764,7 @@ impl<'tcx> Instance<'tcx> { self.def.has_polymorphic_mir_body().then_some(self.args) } - pub fn instantiate_mir(&self, tcx: TyCtxt<'tcx>, v: EarlyBinder<&T>) -> T + pub fn instantiate_mir(&self, tcx: TyCtxt<'tcx>, v: EarlyBinder<'tcx, &T>) -> T where T: TypeFoldable> + Copy, { @@ -782,7 +782,7 @@ impl<'tcx> Instance<'tcx> { &self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - v: EarlyBinder, + v: EarlyBinder<'tcx, T>, ) -> T where T: TypeFoldable>, @@ -800,7 +800,7 @@ impl<'tcx> Instance<'tcx> { &self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - v: EarlyBinder, + v: EarlyBinder<'tcx, T>, ) -> Result> where T: TypeFoldable>, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 79cfeb71d47e..f24074cb472d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -114,9 +114,9 @@ pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::{ AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs, - CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig, InlineConstArgs, - InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, - VarianceDiagInfo, + CoroutineClosureArgsParts, CoroutineClosureSignature, EarlyBinder, FnSig, GenSig, + InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, + UpvarArgs, VarianceDiagInfo, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ @@ -266,7 +266,7 @@ pub struct ImplHeader<'tcx> { #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub struct ImplTraitHeader<'tcx> { - pub trait_ref: ty::EarlyBinder>, + pub trait_ref: ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>, pub polarity: ImplPolarity, pub safety: hir::Safety, } diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index e2cfabfdafaa..fb16cf5bd363 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -125,7 +125,7 @@ impl<'tcx> TyCtxt<'tcx> { self, param_args: GenericArgsRef<'tcx>, param_env: ty::ParamEnv<'tcx>, - value: EarlyBinder, + value: EarlyBinder<'tcx, T>, ) -> T where T: TypeFoldable>, @@ -143,7 +143,7 @@ impl<'tcx> TyCtxt<'tcx> { self, param_args: GenericArgsRef<'tcx>, param_env: ty::ParamEnv<'tcx>, - value: EarlyBinder, + value: EarlyBinder<'tcx, T>, ) -> Result> where T: TypeFoldable>, diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 571c6e918dcb..f394b3c990ce 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -33,8 +33,8 @@ impl ParameterizedOverTcx for ty::Binder<'static, T> { type Value<'tcx> = ty::Binder<'tcx, T::Value<'tcx>>; } -impl ParameterizedOverTcx for ty::EarlyBinder { - type Value<'tcx> = ty::EarlyBinder>; +impl ParameterizedOverTcx for ty::EarlyBinder<'static, T> { + type Value<'tcx> = ty::EarlyBinder<'tcx, T::Value<'tcx>>; } #[macro_export] diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 0807cbf91d16..4e85af901707 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -138,6 +138,14 @@ impl<'tcx> Region<'tcx> { } impl<'tcx> rustc_type_ir::inherent::Region> for Region<'tcx> { + fn new_bound( + interner: TyCtxt<'tcx>, + debruijn: ty::DebruijnIndex, + var: ty::BoundRegion, + ) -> Self { + Region::new_bound(interner, debruijn, var) + } + fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::BrAnon }) } @@ -327,6 +335,12 @@ pub struct EarlyParamRegion { pub name: Symbol, } +impl rustc_type_ir::inherent::ParamLike for EarlyParamRegion { + fn index(self) -> u32 { + self.index + } +} + impl std::fmt::Debug for EarlyParamRegion { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}/#{}", self.name, self.index) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 40f3db89df56..5cf96d298375 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -40,6 +40,7 @@ pub type TypeAndMut<'tcx> = ir::TypeAndMut>; pub type AliasTy<'tcx> = ir::AliasTy>; pub type FnSig<'tcx> = ir::FnSig>; pub type Binder<'tcx, T> = ir::Binder, T>; +pub type EarlyBinder<'tcx, T> = ir::EarlyBinder, T>; pub trait Article { fn article(&self) -> &'static str; @@ -954,6 +955,12 @@ pub struct ParamTy { pub name: Symbol, } +impl rustc_type_ir::inherent::ParamLike for ParamTy { + fn index(self) -> u32 { + self.index + } +} + impl<'tcx> ParamTy { pub fn new(index: u32, name: Symbol) -> ParamTy { ParamTy { index, name } @@ -982,6 +989,12 @@ pub struct ParamConst { pub name: Symbol, } +impl rustc_type_ir::inherent::ParamLike for ParamConst { + fn index(self) -> u32 { + self.index + } +} + impl ParamConst { pub fn new(index: u32, name: Symbol) -> ParamConst { ParamConst { index, name } @@ -1423,6 +1436,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { Ty::new_var(tcx, vid) } + fn new_bound(interner: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundTy) -> Self { + Ty::new_bound(interner, debruijn, var) + } + fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon }) } @@ -2055,7 +2072,7 @@ impl<'tcx> Ty<'tcx> { fn async_destructor_combinator( tcx: TyCtxt<'tcx>, lang_item: LangItem, - ) -> ty::EarlyBinder> { + ) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { tcx.fn_sig(tcx.require_lang_item(lang_item, None)) .map_bound(|fn_sig| fn_sig.output().no_bound_vars().unwrap()) } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 5a3d90221ebd..cacaa859d526 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -694,7 +694,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn coroutine_hidden_types( self, def_id: DefId, - ) -> impl Iterator>> { + ) -> impl Iterator>> { let coroutine_layout = self.mir_coroutine_witnesses(def_id); coroutine_layout .as_ref() @@ -709,7 +709,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn bound_coroutine_hidden_types( self, def_id: DefId, - ) -> impl Iterator>>> { + ) -> impl Iterator>>> { let coroutine_layout = self.mir_coroutine_witnesses(def_id); coroutine_layout .as_ref() diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 79f36cfe5695..4ae475d35d14 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -23,7 +23,7 @@ impl<'tcx> Value> for Ty<'_> { } } -impl<'tcx> Value> for Result>, CyclePlaceholder> { +impl<'tcx> Value> for Result>, CyclePlaceholder> { fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self { Err(CyclePlaceholder(guar)) } @@ -111,7 +111,7 @@ impl<'tcx> Value> for Representability { } } -impl<'tcx> Value> for ty::EarlyBinder> { +impl<'tcx> Value> for ty::EarlyBinder<'_, Ty<'_>> { fn from_cycle_error( tcx: TyCtxt<'tcx>, cycle_error: &CycleError, @@ -121,7 +121,7 @@ impl<'tcx> Value> for ty::EarlyBinder> { } } -impl<'tcx> Value> for ty::EarlyBinder>> { +impl<'tcx> Value> for ty::EarlyBinder<'_, ty::Binder<'_, ty::FnSig<'_>>> { fn from_cycle_error( tcx: TyCtxt<'tcx>, cycle_error: &CycleError, diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 66cc65de6470..6df32169eecb 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -689,8 +689,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if Some(adt_def.did()) == self.tcx.lang_items().dyn_metadata() { self.fail( location, - format!("You can't project to field {f:?} of `DynMetadata` because \ - layout is weird and thinks it doesn't have fields."), + format!( + "You can't project to field {f:?} of `DynMetadata` because \ + layout is weird and thinks it doesn't have fields." + ), ); } @@ -839,7 +841,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { && cntxt != PlaceContext::NonUse(NonUseContext::VarDebugInfo) && place.projection[1..].contains(&ProjectionElem::Deref) { - self.fail(location, format!("{place:?}, has deref at the wrong place")); + self.fail( + location, + format!("place {place:?} has deref as a later projection (it is only permitted as the first projection)"), + ); + } + + // Ensure all downcast projections are followed by field projections. + let mut projections_iter = place.projection.iter(); + while let Some(proj) = projections_iter.next() { + if matches!(proj, ProjectionElem::Downcast(..)) { + if !matches!(projections_iter.next(), Some(ProjectionElem::Field(..))) { + self.fail( + location, + format!( + "place {place:?} has `Downcast` projection not followed by `Field`" + ), + ); + } + } } self.super_place(place, cntxt, location); diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index a511989d972c..66708def00f1 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -194,7 +194,7 @@ where } } -impl<'tcx, S, V> Stable<'tcx> for ty::EarlyBinder +impl<'tcx, S, V> Stable<'tcx> for ty::EarlyBinder<'tcx, S> where S: Stable<'tcx, T = V>, { diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 9590a82c0677..f6ec65490845 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -99,6 +99,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { previous call to `try_evaluate_added_goals!`" ); + // We only check for leaks from universes which were entered inside + // of the query. + self.infcx.leak_check(self.max_input_universe, None).map_err(|e| { + trace!(?e, "failed the leak check"); + NoSolution + })?; + // When normalizing, we've replaced the expected term with an unconstrained // inference variable. This means that we dropped information which could // have been important. We handle this by instead returning the nested goals @@ -121,7 +128,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { }; let external_constraints = - self.compute_external_query_constraints(normalization_nested_goals)?; + self.compute_external_query_constraints(certainty, normalization_nested_goals); let (var_values, mut external_constraints) = (self.var_values, external_constraints).fold_with(&mut EagerResolver::new(self.infcx)); // Remove any trivial region constraints once we've resolved regions @@ -170,30 +177,37 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self), ret)] fn compute_external_query_constraints( &self, + certainty: Certainty, normalization_nested_goals: NestedNormalizationGoals<'tcx>, - ) -> Result, NoSolution> { - // We only check for leaks from universes which were entered inside - // of the query. - self.infcx.leak_check(self.max_input_universe, None).map_err(|e| { - trace!(?e, "failed the leak check"); - NoSolution - })?; + ) -> ExternalConstraintsData<'tcx> { + // We only return region constraints once the certainty is `Yes`. This + // is necessary as we may drop nested goals on ambiguity, which may result + // in unconstrained inference variables in the region constraints. It also + // prevents us from emitting duplicate region constraints, avoiding some + // unnecessary work. This slightly weakens the leak check in case it uses + // region constraints from an ambiguous nested goal. This is tested in both + // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs` and + // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`. + let region_constraints = if certainty == Certainty::Yes { + // Cannot use `take_registered_region_obligations` as we may compute the response + // inside of a `probe` whenever we have multiple choices inside of the solver. + let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); + let mut region_constraints = self.infcx.with_region_constraints(|region_constraints| { + make_query_region_constraints( + self.tcx(), + region_obligations.iter().map(|r_o| { + (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category()) + }), + region_constraints, + ) + }); - // Cannot use `take_registered_region_obligations` as we may compute the response - // inside of a `probe` whenever we have multiple choices inside of the solver. - let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); - let mut region_constraints = self.infcx.with_region_constraints(|region_constraints| { - make_query_region_constraints( - self.tcx(), - region_obligations - .iter() - .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())), - region_constraints, - ) - }); - - let mut seen = FxHashSet::default(); - region_constraints.outlives.retain(|outlives| seen.insert(*outlives)); + let mut seen = FxHashSet::default(); + region_constraints.outlives.retain(|outlives| seen.insert(*outlives)); + region_constraints + } else { + Default::default() + }; let mut opaque_types = self.infcx.clone_opaque_types_for_query_response(); // Only return opaque type keys for newly-defined opaques @@ -201,7 +215,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a) }); - Ok(ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals }) + ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } } /// After calling a canonical query, we apply the constraints returned diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 77ac4be35ea1..87c8b1cda504 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -2097,7 +2097,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_ty.defining_node); let ty = tcx.type_of(assoc_ty.item.def_id); let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst); - let term: ty::EarlyBinder> = if is_const { + let term: ty::EarlyBinder<'tcx, ty::Term<'tcx>> = if is_const { let did = assoc_ty.item.def_id; let identity_args = crate::traits::GenericArgs::identity_for_item(tcx, did); let uv = ty::UnevaluatedConst::new(did, identity_args); diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 67ffb8a58b5a..58447f6d6a31 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -398,10 +398,10 @@ impl<'a, 'tcx> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> { } /// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead. -fn thir_abstract_const( - tcx: TyCtxt<'_>, +fn thir_abstract_const<'tcx>( + tcx: TyCtxt<'tcx>, def: LocalDefId, -) -> Result>>, ErrorGuaranteed> { +) -> Result>>, ErrorGuaranteed> { if !tcx.features().generic_const_exprs { return Ok(None); } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 617e8a543656..38950c97c9d5 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -77,7 +77,7 @@ fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness { fn adt_sized_constraint<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, -) -> Option>> { +) -> Option>> { if let Some(def_id) = def_id.as_local() { if let ty::Representability::Infinite(_) = tcx.representability(def_id) { return None; @@ -253,7 +253,7 @@ fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamE fn self_ty_of_trait_impl_enabling_order_dep_trait_object_hack( tcx: TyCtxt<'_>, def_id: DefId, -) -> Option>> { +) -> Option>> { let impl_ = tcx.impl_trait_header(def_id).unwrap_or_else(|| bug!("called on inherent impl {def_id:?}")); diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index cef3f4e8ce05..18a09067a2c9 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -15,6 +15,7 @@ rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_span = { path = "../rustc_span", optional = true } rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } smallvec = { version = "1.8.1", default-features = false } +tracing = "0.1" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 5336b915a1d3..e50d59ba5f0e 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -1,12 +1,14 @@ use std::fmt::Debug; use std::hash::Hash; +use std::marker::PhantomData; use std::ops::{ControlFlow, Deref}; #[cfg(feature = "nightly")] -use rustc_macros::HashStable_NoContext; +use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_serialize::Decodable; +use tracing::debug; -use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; +use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; use crate::inherent::*; use crate::lift::Lift; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; @@ -338,3 +340,516 @@ impl TypeVisitor for ValidateBoundVars { ControlFlow::Continue(()) } } + +/// Similar to [`super::Binder`] except that it tracks early bound generics, i.e. `struct Foo(T)` +/// needs `T` instantiated immediately. This type primarily exists to avoid forgetting to call +/// `instantiate`. +/// +/// If you don't have anything to `instantiate`, you may be looking for +/// [`instantiate_identity`](EarlyBinder::instantiate_identity) or [`skip_binder`](EarlyBinder::skip_binder). +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = "T: Clone"), + Copy(bound = "T: Copy"), + PartialEq(bound = "T: PartialEq"), + Eq(bound = "T: Eq"), + Ord(bound = "T: Ord"), + PartialOrd(bound = "T: Ord"), + Hash(bound = "T: Hash"), + Debug(bound = "T: Debug") +)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +pub struct EarlyBinder { + value: T, + _tcx: PhantomData, +} + +/// For early binders, you should first call `instantiate` before using any visitors. +#[cfg(feature = "nightly")] +impl !TypeFoldable for ty::EarlyBinder {} + +/// For early binders, you should first call `instantiate` before using any visitors. +#[cfg(feature = "nightly")] +impl !TypeVisitable for ty::EarlyBinder {} + +impl EarlyBinder { + pub fn bind(value: T) -> EarlyBinder { + EarlyBinder { value, _tcx: PhantomData } + } + + pub fn as_ref(&self) -> EarlyBinder { + EarlyBinder { value: &self.value, _tcx: PhantomData } + } + + pub fn map_bound_ref(&self, f: F) -> EarlyBinder + where + F: FnOnce(&T) -> U, + { + self.as_ref().map_bound(f) + } + + pub fn map_bound(self, f: F) -> EarlyBinder + where + F: FnOnce(T) -> U, + { + let value = f(self.value); + EarlyBinder { value, _tcx: PhantomData } + } + + pub fn try_map_bound(self, f: F) -> Result, E> + where + F: FnOnce(T) -> Result, + { + let value = f(self.value)?; + Ok(EarlyBinder { value, _tcx: PhantomData }) + } + + pub fn rebind(&self, value: U) -> EarlyBinder { + EarlyBinder { value, _tcx: PhantomData } + } + + /// Skips the binder and returns the "bound" value. + /// This can be used to extract data that does not depend on generic parameters + /// (e.g., getting the `DefId` of the inner value or getting the number of + /// arguments of an `FnSig`). Otherwise, consider using + /// [`instantiate_identity`](EarlyBinder::instantiate_identity). + /// + /// To skip the binder on `x: &EarlyBinder` to obtain `&T`, leverage + /// [`EarlyBinder::as_ref`](EarlyBinder::as_ref): `x.as_ref().skip_binder()`. + /// + /// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is + /// the analogous operation on [`super::Binder`]. + pub fn skip_binder(self) -> T { + self.value + } +} + +impl EarlyBinder> { + pub fn transpose(self) -> Option> { + self.value.map(|value| EarlyBinder { value, _tcx: PhantomData }) + } +} + +impl<'s, I: Interner, Iter: IntoIterator> EarlyBinder +where + Iter::Item: TypeFoldable, +{ + pub fn iter_instantiated( + self, + tcx: I, + args: &'s [I::GenericArg], + ) -> IterInstantiated<'s, I, Iter> { + IterInstantiated { it: self.value.into_iter(), tcx, args } + } + + /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity), + /// but on an iterator of `TypeFoldable` values. + pub fn instantiate_identity_iter(self) -> Iter::IntoIter { + self.value.into_iter() + } +} + +pub struct IterInstantiated<'s, I: Interner, Iter: IntoIterator> { + it: Iter::IntoIter, + tcx: I, + args: &'s [I::GenericArg], +} + +impl Iterator for IterInstantiated<'_, I, Iter> +where + Iter::Item: TypeFoldable, +{ + type Item = Iter::Item; + + fn next(&mut self) -> Option { + Some( + EarlyBinder { value: self.it.next()?, _tcx: PhantomData } + .instantiate(self.tcx, self.args), + ) + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl DoubleEndedIterator for IterInstantiated<'_, I, Iter> +where + Iter::IntoIter: DoubleEndedIterator, + Iter::Item: TypeFoldable, +{ + fn next_back(&mut self) -> Option { + Some( + EarlyBinder { value: self.it.next_back()?, _tcx: PhantomData } + .instantiate(self.tcx, self.args), + ) + } +} + +impl ExactSizeIterator for IterInstantiated<'_, I, Iter> +where + Iter::IntoIter: ExactSizeIterator, + Iter::Item: TypeFoldable, +{ +} + +impl<'s, I: Interner, Iter: IntoIterator> EarlyBinder +where + Iter::Item: Deref, + ::Target: Copy + TypeFoldable, +{ + pub fn iter_instantiated_copied( + self, + tcx: I, + args: &'s [I::GenericArg], + ) -> IterInstantiatedCopied<'s, I, Iter> { + IterInstantiatedCopied { it: self.value.into_iter(), tcx, args } + } + + /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity), + /// but on an iterator of values that deref to a `TypeFoldable`. + pub fn instantiate_identity_iter_copied( + self, + ) -> impl Iterator::Target> { + self.value.into_iter().map(|v| *v) + } +} + +pub struct IterInstantiatedCopied<'a, I: Interner, Iter: IntoIterator> { + it: Iter::IntoIter, + tcx: I, + args: &'a [I::GenericArg], +} + +impl Iterator for IterInstantiatedCopied<'_, I, Iter> +where + Iter::Item: Deref, + ::Target: Copy + TypeFoldable, +{ + type Item = ::Target; + + fn next(&mut self) -> Option { + self.it.next().map(|value| { + EarlyBinder { value: *value, _tcx: PhantomData }.instantiate(self.tcx, self.args) + }) + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl DoubleEndedIterator for IterInstantiatedCopied<'_, I, Iter> +where + Iter::IntoIter: DoubleEndedIterator, + Iter::Item: Deref, + ::Target: Copy + TypeFoldable, +{ + fn next_back(&mut self) -> Option { + self.it.next_back().map(|value| { + EarlyBinder { value: *value, _tcx: PhantomData }.instantiate(self.tcx, self.args) + }) + } +} + +impl ExactSizeIterator for IterInstantiatedCopied<'_, I, Iter> +where + Iter::IntoIter: ExactSizeIterator, + Iter::Item: Deref, + ::Target: Copy + TypeFoldable, +{ +} + +pub struct EarlyBinderIter { + t: T, + _tcx: PhantomData, +} + +impl EarlyBinder { + pub fn transpose_iter(self) -> EarlyBinderIter { + EarlyBinderIter { t: self.value.into_iter(), _tcx: PhantomData } + } +} + +impl Iterator for EarlyBinderIter { + type Item = EarlyBinder; + + fn next(&mut self) -> Option { + self.t.next().map(|value| EarlyBinder { value, _tcx: PhantomData }) + } + + fn size_hint(&self) -> (usize, Option) { + self.t.size_hint() + } +} + +impl> ty::EarlyBinder { + pub fn instantiate(self, tcx: I, args: &[I::GenericArg]) -> T { + let mut folder = ArgFolder { tcx, args, binders_passed: 0 }; + self.value.fold_with(&mut folder) + } + + /// Makes the identity replacement `T0 => T0, ..., TN => TN`. + /// Conceptually, this converts universally bound variables into placeholders + /// when inside of a given item. + /// + /// For example, consider `for fn foo(){ .. }`: + /// - Outside of `foo`, `T` is bound (represented by the presence of `EarlyBinder`). + /// - Inside of the body of `foo`, we treat `T` as a placeholder by calling + /// `instantiate_identity` to discharge the `EarlyBinder`. + pub fn instantiate_identity(self) -> T { + self.value + } + + /// Returns the inner value, but only if it contains no bound vars. + pub fn no_bound_vars(self) -> Option { + if !self.value.has_param() { Some(self.value) } else { None } + } +} + +/////////////////////////////////////////////////////////////////////////// +// The actual instantiation engine itself is a type folder. + +struct ArgFolder<'a, I: Interner> { + tcx: I, + args: &'a [I::GenericArg], + + /// Number of region binders we have passed through while doing the instantiation + binders_passed: u32, +} + +impl<'a, I: Interner> TypeFolder for ArgFolder<'a, I> { + #[inline] + fn interner(&self) -> I { + self.tcx + } + + fn fold_binder>(&mut self, t: ty::Binder) -> ty::Binder { + self.binders_passed += 1; + let t = t.super_fold_with(self); + self.binders_passed -= 1; + t + } + + fn fold_region(&mut self, r: I::Region) -> I::Region { + // Note: This routine only handles regions that are bound on + // type declarations and other outer declarations, not those + // bound in *fn types*. Region instantiation of the bound + // regions that appear in a function signature is done using + // the specialized routine `ty::replace_late_regions()`. + match r.kind() { + ty::ReEarlyParam(data) => { + let rk = self.args.get(data.index() as usize).map(|k| k.kind()); + match rk { + Some(ty::GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt), + Some(other) => self.region_param_expected(data, r, other), + None => self.region_param_out_of_range(data, r), + } + } + ty::ReBound(..) + | ty::ReLateParam(_) + | ty::ReStatic + | ty::RePlaceholder(_) + | ty::ReErased + | ty::ReError(_) => r, + ty::ReVar(_) => panic!("unexpected region: {r:?}"), + } + } + + fn fold_ty(&mut self, t: I::Ty) -> I::Ty { + if !t.has_param() { + return t; + } + + match t.kind() { + ty::Param(p) => self.ty_for_param(p, t), + _ => t.super_fold_with(self), + } + } + + fn fold_const(&mut self, c: I::Const) -> I::Const { + if let ty::ConstKind::Param(p) = c.kind() { + self.const_for_param(p, c) + } else { + c.super_fold_with(self) + } + } +} + +impl<'a, I: Interner> ArgFolder<'a, I> { + fn ty_for_param(&self, p: I::ParamTy, source_ty: I::Ty) -> I::Ty { + // Look up the type in the args. It really should be in there. + let opt_ty = self.args.get(p.index() as usize).map(|k| k.kind()); + let ty = match opt_ty { + Some(ty::GenericArgKind::Type(ty)) => ty, + Some(kind) => self.type_param_expected(p, source_ty, kind), + None => self.type_param_out_of_range(p, source_ty), + }; + + self.shift_vars_through_binders(ty) + } + + #[cold] + #[inline(never)] + fn type_param_expected(&self, p: I::ParamTy, ty: I::Ty, kind: ty::GenericArgKind) -> ! { + panic!( + "expected type for `{:?}` ({:?}/{}) but found {:?} when instantiating, args={:?}", + p, + ty, + p.index(), + kind, + self.args, + ) + } + + #[cold] + #[inline(never)] + fn type_param_out_of_range(&self, p: I::ParamTy, ty: I::Ty) -> ! { + panic!( + "type parameter `{:?}` ({:?}/{}) out of range when instantiating, args={:?}", + p, + ty, + p.index(), + self.args, + ) + } + + fn const_for_param(&self, p: I::ParamConst, source_ct: I::Const) -> I::Const { + // Look up the const in the args. It really should be in there. + let opt_ct = self.args.get(p.index() as usize).map(|k| k.kind()); + let ct = match opt_ct { + Some(ty::GenericArgKind::Const(ct)) => ct, + Some(kind) => self.const_param_expected(p, source_ct, kind), + None => self.const_param_out_of_range(p, source_ct), + }; + + self.shift_vars_through_binders(ct) + } + + #[cold] + #[inline(never)] + fn const_param_expected( + &self, + p: I::ParamConst, + ct: I::Const, + kind: ty::GenericArgKind, + ) -> ! { + panic!( + "expected const for `{:?}` ({:?}/{}) but found {:?} when instantiating args={:?}", + p, + ct, + p.index(), + kind, + self.args, + ) + } + + #[cold] + #[inline(never)] + fn const_param_out_of_range(&self, p: I::ParamConst, ct: I::Const) -> ! { + panic!( + "const parameter `{:?}` ({:?}/{}) out of range when instantiating args={:?}", + p, + ct, + p.index(), + self.args, + ) + } + + #[cold] + #[inline(never)] + fn region_param_expected( + &self, + ebr: I::EarlyParamRegion, + r: I::Region, + kind: ty::GenericArgKind, + ) -> ! { + panic!( + "expected region for `{:?}` ({:?}/{}) but found {:?} when instantiating args={:?}", + ebr, + r, + ebr.index(), + kind, + self.args, + ) + } + + #[cold] + #[inline(never)] + fn region_param_out_of_range(&self, ebr: I::EarlyParamRegion, r: I::Region) -> ! { + panic!( + "const parameter `{:?}` ({:?}/{}) out of range when instantiating args={:?}", + ebr, + r, + ebr.index(), + self.args, + ) + } + + /// It is sometimes necessary to adjust the De Bruijn indices during instantiation. This occurs + /// when we are instantating a type with escaping bound vars into a context where we have + /// passed through binders. That's quite a mouthful. Let's see an example: + /// + /// ``` + /// type Func = fn(A); + /// type MetaFunc = for<'a> fn(Func<&'a i32>); + /// ``` + /// + /// The type `MetaFunc`, when fully expanded, will be + /// ```ignore (illustrative) + /// for<'a> fn(fn(&'a i32)) + /// // ^~ ^~ ^~~ + /// // | | | + /// // | | DebruijnIndex of 2 + /// // Binders + /// ``` + /// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the + /// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip + /// over the inner binder (remember that we count De Bruijn indices from 1). However, in the + /// definition of `MetaFunc`, the binder is not visible, so the type `&'a i32` will have a + /// De Bruijn index of 1. It's only during the instantiation that we can see we must increase the + /// depth by 1 to account for the binder that we passed through. + /// + /// As a second example, consider this twist: + /// + /// ``` + /// type FuncTuple = (A,fn(A)); + /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a i32>); + /// ``` + /// + /// Here the final type will be: + /// ```ignore (illustrative) + /// for<'a> fn((&'a i32, fn(&'a i32))) + /// // ^~~ ^~~ + /// // | | + /// // DebruijnIndex of 1 | + /// // DebruijnIndex of 2 + /// ``` + /// As indicated in the diagram, here the same type `&'a i32` is instantiated once, but in the + /// first case we do not increase the De Bruijn index and in the second case we do. The reason + /// is that only in the second case have we passed through a fn binder. + fn shift_vars_through_binders>(&self, val: T) -> T { + debug!( + "shift_vars(val={:?}, binders_passed={:?}, has_escaping_bound_vars={:?})", + val, + self.binders_passed, + val.has_escaping_bound_vars() + ); + + if self.binders_passed == 0 || !val.has_escaping_bound_vars() { + return val; + } + + let result = ty::fold::shift_vars(TypeFolder::interner(self), val, self.binders_passed); + debug!("shift_vars: shifted result = {:?}", result); + + result + } + + fn shift_region_through_binders(&self, region: I::Region) -> I::Region { + if self.binders_passed == 0 || !region.has_escaping_bound_vars() { + return region; + } + ty::fold::shift_region(self.tcx, region, self.binders_passed) + } +} diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 405aba30241b..501311ff72f7 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -47,8 +47,10 @@ use rustc_index::{Idx, IndexVec}; use std::mem; +use tracing::debug; -use crate::visit::TypeVisitable; +use crate::inherent::*; +use crate::visit::{TypeVisitable, TypeVisitableExt as _}; use crate::{self as ty, Interner, Lrc}; #[cfg(feature = "nightly")] @@ -325,3 +327,95 @@ impl, Ix: Idx> TypeFoldable for IndexVec { + tcx: I, + current_index: ty::DebruijnIndex, + amount: u32, +} + +impl Shifter { + pub fn new(tcx: I, amount: u32) -> Self { + Shifter { tcx, current_index: ty::INNERMOST, amount } + } +} + +impl TypeFolder for Shifter { + fn interner(&self) -> I { + self.tcx + } + + fn fold_binder>(&mut self, t: ty::Binder) -> ty::Binder { + self.current_index.shift_in(1); + let t = t.super_fold_with(self); + self.current_index.shift_out(1); + t + } + + fn fold_region(&mut self, r: I::Region) -> I::Region { + match r.kind() { + ty::ReBound(debruijn, br) if debruijn >= self.current_index => { + let debruijn = debruijn.shifted_in(self.amount); + Region::new_bound(self.tcx, debruijn, br) + } + _ => r, + } + } + + fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { + match ty.kind() { + ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { + let debruijn = debruijn.shifted_in(self.amount); + Ty::new_bound(self.tcx, debruijn, bound_ty) + } + + _ if ty.has_vars_bound_at_or_above(self.current_index) => ty.super_fold_with(self), + _ => ty, + } + } + + fn fold_const(&mut self, ct: I::Const) -> I::Const { + match ct.kind() { + ty::ConstKind::Bound(debruijn, bound_ct) if debruijn >= self.current_index => { + let debruijn = debruijn.shifted_in(self.amount); + Const::new_bound(self.tcx, debruijn, bound_ct, ct.ty()) + } + _ => ct.super_fold_with(self), + } + } + + fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } + } +} + +pub fn shift_region(tcx: I, region: I::Region, amount: u32) -> I::Region { + match region.kind() { + ty::ReBound(debruijn, br) if amount > 0 => { + Region::new_bound(tcx, debruijn.shifted_in(amount), br) + } + _ => region, + } +} + +pub fn shift_vars(tcx: I, value: T, amount: u32) -> T +where + T: TypeFoldable, +{ + debug!("shift_vars(value={:?}, amount={})", value, amount); + + if amount == 0 || !value.has_escaping_bound_vars() { + return value; + } + + value.fold_with(&mut Shifter::new(tcx, amount)) +} diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 77fe30a46608..e7e893f27daa 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -29,6 +29,8 @@ pub trait Ty>: fn new_var(interner: I, var: ty::TyVid) -> Self; + fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundTy) -> Self; + fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy) -> Self; @@ -65,7 +67,10 @@ pub trait Region>: + Into + IntoKind> + Flags + + TypeVisitable { + fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundRegion) -> Self; + fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; fn new_static(interner: I) -> Self; @@ -87,6 +92,8 @@ pub trait Const>: fn new_var(interner: I, var: ty::ConstVid, ty: I::Ty) -> Self; + fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundConst, ty: I::Ty) -> Self; + fn new_anon_bound( interner: I, debruijn: ty::DebruijnIndex, @@ -162,3 +169,7 @@ pub trait BoundVarLike { fn assert_eq(self, var: I::BoundVarKind); } + +pub trait ParamLike { + fn index(self) -> u32; +} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index c77414afc52c..e49db171a534 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -7,26 +7,22 @@ use crate::inherent::*; use crate::ir_print::IrPrint; use crate::solve::inspect::CanonicalGoalEvaluationStep; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; -use crate::{ - AliasTerm, AliasTermKind, AliasTy, AliasTyKind, CanonicalVarInfo, CoercePredicate, - DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, FnSig, GenericArgKind, - NormalizesTo, ProjectionPredicate, SubtypePredicate, TermKind, TraitPredicate, TraitRef, -}; +use crate::{self as ty, DebugWithInfcx}; pub trait Interner: Sized + Copy - + IrPrint> - + IrPrint> - + IrPrint> - + IrPrint> - + IrPrint> - + IrPrint> - + IrPrint> - + IrPrint> - + IrPrint> - + IrPrint> - + IrPrint> + + IrPrint> + + IrPrint> + + IrPrint> + + IrPrint> + + IrPrint> + + IrPrint> + + IrPrint> + + IrPrint> + + IrPrint> + + IrPrint> + + IrPrint> { type DefId: Copy + Debug + Hash + Eq + TypeVisitable; type AdtDef: Copy + Debug + Hash + Eq; @@ -39,9 +35,9 @@ pub trait Interner: + DebugWithInfcx + Hash + Eq - + IntoKind> + + IntoKind> + TypeVisitable; - type Term: Copy + Debug + Hash + Eq + IntoKind> + TypeVisitable; + type Term: Copy + Debug + Hash + Eq + IntoKind> + TypeVisitable; type BoundVarKinds: Copy + Debug @@ -51,7 +47,7 @@ pub trait Interner: + Default; type BoundVarKind: Copy + Debug + Hash + Eq; - type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator>; + type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator>; type PredefinedOpaques: Copy + Debug + Hash + Eq; type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable; type ExternalConstraints: Copy + Debug + Hash + Eq; @@ -65,7 +61,7 @@ pub trait Interner: type Ty: Ty; type Tys: Tys; type FnInputTys: Copy + Debug + Hash + Eq + Deref + TypeVisitable; - type ParamTy: Copy + Debug + Hash + Eq; + type ParamTy: Copy + Debug + Hash + Eq + ParamLike; type BoundTy: Copy + Debug + Hash + Eq + BoundVarLike; type PlaceholderTy: PlaceholderLike; @@ -81,14 +77,14 @@ pub trait Interner: // Kinds of consts type Const: Const; type PlaceholderConst: PlaceholderLike; - type ParamConst: Copy + Debug + Hash + Eq; + type ParamConst: Copy + Debug + Hash + Eq + ParamLike; type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike; type ValueConst: Copy + Debug + Hash + Eq; type ExprConst: Copy + DebugWithInfcx + Hash + Eq; // Kinds of regions type Region: Region; - type EarlyParamRegion: Copy + Debug + Hash + Eq; + type EarlyParamRegion: Copy + Debug + Hash + Eq + ParamLike; type LateParamRegion: Copy + Debug + Hash + Eq; type BoundRegion: Copy + Debug + Hash + Eq + BoundVarLike; type PlaceholderRegion: PlaceholderLike; @@ -99,23 +95,23 @@ pub trait Interner: type Clause: Clause; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable + Flags; - fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo]) -> Self::CanonicalVars; + fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars; type GenericsOf: GenericsOf; fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf; // FIXME: Remove after uplifting `EarlyBinder` - fn type_of_instantiated(self, def_id: Self::DefId, args: Self::GenericArgs) -> Self::Ty; + fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder; - fn alias_ty_kind(self, alias: AliasTy) -> AliasTyKind; + fn alias_ty_kind(self, alias: ty::AliasTy) -> ty::AliasTyKind; - fn alias_term_kind(self, alias: AliasTerm) -> AliasTermKind; + fn alias_term_kind(self, alias: ty::AliasTerm) -> ty::AliasTermKind; fn trait_ref_and_own_args_for_alias( self, def_id: Self::DefId, args: Self::GenericArgs, - ) -> (TraitRef, Self::OwnItemArgs); + ) -> (ty::TraitRef, Self::OwnItemArgs); fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 4a461b5b5f3c..217c056d0bae 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -1,6 +1,6 @@ #![cfg_attr( feature = "nightly", - feature(associated_type_defaults, min_specialization, never_type, rustc_attrs) + feature(associated_type_defaults, min_specialization, never_type, rustc_attrs, negative_impls) )] #![allow(rustc::usage_of_ty_tykind)] #![cfg_attr(feature = "nightly", allow(internal_features))] diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 4e12c6b3d671..48a6f79993cc 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -567,7 +567,7 @@ impl AliasTerm { I::Const::new_unevaluated( interner, ty::UnevaluatedConst::new(self.def_id, self.args), - interner.type_of_instantiated(self.def_id, self.args), + interner.type_of(self.def_id).instantiate(interner, &self.args), ) .into() } diff --git a/config.example.toml b/config.example.toml index 228521747ede..61655dad6385 100644 --- a/config.example.toml +++ b/config.example.toml @@ -904,9 +904,6 @@ # on linux #src-tarball = true -# Whether to allow failures when building tools -#missing-tools = false - # List of compression formats to use when generating dist tarballs. The list of # formats is provided to rust-installer, which must support all of them. # diff --git a/library/backtrace b/library/backtrace index e15130618237..5e05efa87905 160000 --- a/library/backtrace +++ b/library/backtrace @@ -1 +1 @@ -Subproject commit e15130618237eb3e2d4b622549f9647b4c1d9ca3 +Subproject commit 5e05efa87905fb5b351a2bc5644d60c57d6d9327 diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 1e3ed0f7c49f..9a527073602e 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -137,10 +137,13 @@ //! //! [^extern_fn]: this remains true for any argument/return types and any other ABI: `extern "abi" fn` (_e.g._, `extern "system" fn`) //! +//! Under some conditions the above types `T` are also null pointer optimized when wrapped in a [`Result`][result_repr]. +//! //! [`Box`]: ../../std/boxed/struct.Box.html //! [`num::NonZero*`]: crate::num //! [`ptr::NonNull`]: crate::ptr::NonNull //! [function call ABI]: ../primitive.fn.html#abi-compatibility +//! [result_repr]: crate::result#representation //! //! This is called the "null pointer optimization" or NPO. //! diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 4c6dc4bba437..f8cdcc000c50 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -228,6 +228,27 @@ //! [`Err(E)`]: Err //! [io::Error]: ../../std/io/struct.Error.html "io::Error" //! +//! # Representation +//! +//! In some cases, [`Result`] will gain the same size, alignment, and ABI +//! guarantees as [`Option`] has. One of either the `T` or `E` type must be a +//! type that qualifies for the `Option` [representation guarantees][opt-rep], +//! and the *other* type must meet all of the following conditions: +//! * Is a zero-sized type with alignment 1 (a "1-ZST"). +//! * Has no fields. +//! * Does not have the `#[non_exhaustive]` attribute. +//! +//! For example, `NonZeroI32` qualifies for the `Option` representation +//! guarantees, and `()` is a zero-sized type with alignment 1, no fields, and +//! it isn't `non_exhaustive`. This means that both `Result` and +//! `Result<(), NonZeroI32>` have the same size, alignment, and ABI guarantees +//! as `Option`. The only difference is the implied semantics: +//! * `Option` is "a non-zero i32 might be present" +//! * `Result` is "a non-zero i32 success result, if any" +//! * `Result<(), NonZeroI32>` is "a non-zero i32 error result, if any" +//! +//! [opt-rep]: ../option/index.html#representation "Option Representation" +//! //! # Method overview //! //! In addition to working with pattern matching, [`Result`] provides a diff --git a/library/core/src/str/count.rs b/library/core/src/str/count.rs index 28567a7e753a..d8667864fe55 100644 --- a/library/core/src/str/count.rs +++ b/library/core/src/str/count.rs @@ -24,7 +24,7 @@ const UNROLL_INNER: usize = 4; #[inline] pub(super) fn count_chars(s: &str) -> usize { - if s.len() < USIZE_SIZE * UNROLL_INNER { + if cfg!(feature = "optimize_for_size") || s.len() < USIZE_SIZE * UNROLL_INNER { // Avoid entering the optimized implementation for strings where the // difference is not likely to matter, or where it might even be slower. // That said, a ton of thought was not spent on the particular threshold diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index bc78c63c577c..79a504c5a5e2 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -24,11 +24,11 @@ hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] } # Dependencies of the `backtrace` crate -rustc-demangle = { version = "0.1.21", features = ['rustc-dep-of-std'] } +rustc-demangle = { version = "0.1.24", features = ['rustc-dep-of-std'] } [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies] miniz_oxide = { version = "0.7.0", optional = true, default-features = false } -addr2line = { version = "0.21.0", optional = true, default-features = false } +addr2line = { version = "0.22.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] libc = { version = "0.2.153", default-features = false, features = ['rustc-dep-of-std'], public = true } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index d13dc9d1d177..70d32f2f6d95 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -314,7 +314,6 @@ pub struct Config { pub save_toolstates: Option, pub print_step_timings: bool, pub print_step_rusage: bool, - pub missing_tools: bool, // FIXME: Deprecated field. Remove it at 2024. // Fallback musl-root for all targets pub musl_root: Option, @@ -905,7 +904,6 @@ define_config! { sign_folder: Option = "sign-folder", upload_addr: Option = "upload-addr", src_tarball: Option = "src-tarball", - missing_tools: Option = "missing-tools", compression_formats: Option> = "compression-formats", compression_profile: Option = "compression-profile", include_mingw_linker: Option = "include-mingw-linker", @@ -1936,7 +1934,6 @@ impl Config { sign_folder, upload_addr, src_tarball, - missing_tools, compression_formats, compression_profile, include_mingw_linker, @@ -1946,7 +1943,6 @@ impl Config { config.dist_compression_formats = compression_formats; set(&mut config.dist_compression_profile, compression_profile); set(&mut config.rust_dist_src, src_tarball); - set(&mut config.missing_tools, missing_tools); set(&mut config.dist_include_mingw_linker, include_mingw_linker) } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 2f9eaf51c341..bfe3622e40d3 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -190,4 +190,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "`rust.lld` has a new default value of `true` on `x86_64-unknown-linux-gnu`. Starting at stage1, `rust-lld` will thus be this target's default linker. No config changes should be necessary.", }, + ChangeInfo { + change_id: 125535, + severity: ChangeSeverity::Warning, + summary: "Removed `dist.missing-tools` configuration as it was deprecated long time ago.", + }, ]; diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 22dcb808c743..a4c59b3067ea 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -270,7 +270,6 @@ else args="$args --volume $root_dir:/checkout$SRC_MOUNT_OPTION" args="$args --volume $objdir:/checkout/obj" args="$args --volume $HOME/.cargo:/cargo" - args="$args --volume $HOME/rustsrc:$HOME/rustsrc" args="$args --volume /tmp/toolstate:/tmp/toolstate" id=$(id -u) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 05470eebf014..174aaeec6b50 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -61,6 +61,12 @@ envs: try: <<: *production + # The following env var activates faster `try` builds in `opt-dist` by, e.g. + # - building only the more commonly useful components (we rarely need e.g. rust-docs in try + # builds) + # - not running `opt-dist`'s post-optimization smoke tests on the resulting toolchain + # + # If you *want* these to happen however, temporarily uncomment it before triggering a try build. DIST_TRY_BUILD: 1 auto: diff --git a/src/ci/scripts/verify-line-endings.sh b/src/ci/scripts/verify-line-endings.sh index f3cac13ea480..5f4b4aeb0e4e 100755 --- a/src/ci/scripts/verify-line-endings.sh +++ b/src/ci/scripts/verify-line-endings.sh @@ -4,21 +4,21 @@ # We check both in rust-lang/rust and in a submodule to make sure both are # accurate. Submodules are checked out significantly later than the main # repository in this script, so settings can (and do!) change between then. -# -# Linux (and maybe macOS) builders don't currently have dos2unix so just only -# run this step on Windows. set -euo pipefail IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" -if isWindows; then - # print out the git configuration so we can better investigate failures in - # the following - git config --list --show-origin - dos2unix -ih Cargo.lock src/tools/rust-installer/install-template.sh - endings=$(dos2unix -ic Cargo.lock src/tools/rust-installer/install-template.sh) - # if endings has non-zero length, error out - if [ -n "$endings" ]; then exit 1 ; fi +# print out the git configuration so we can better investigate failures in +# the following +git config --list --show-origin +# -U is necessary on Windows to stop grep automatically converting the line ending +endings=$(grep -Ul $(printf '\r$') Cargo.lock src/tools/cargo/Cargo.lock) || true +# if endings has non-zero length, error out +if [[ -n $endings ]]; then + echo "Error: found DOS line endings" + # Print the files with DOS line endings + echo "$endings" + exit 1 fi diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 7aab07c06a33..7490688e36c5 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -627,7 +627,7 @@ impl Item { ) -> hir::FnHeader { let sig = tcx.fn_sig(def_id).skip_binder(); let constness = - if tcx.is_const_fn(def_id) && is_unstable_const_fn(tcx, def_id).is_none() { + if tcx.is_const_fn(def_id) || is_unstable_const_fn(tcx, def_id).is_some() { hir::Constness::Const } else { hir::Constness::NotConst @@ -649,9 +649,8 @@ impl Item { hir::Safety::Unsafe }, abi, - constness: if abi == Abi::RustIntrinsic - && tcx.is_const_fn(def_id) - && is_unstable_const_fn(tcx, def_id).is_none() + constness: if tcx.is_const_fn(def_id) + || is_unstable_const_fn(tcx, def_id).is_some() { hir::Constness::Const } else { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 587c464b0ed1..57949001774f 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -13,7 +13,7 @@ use std::fmt::{self, Display, Write}; use std::iter::{self, once}; use rustc_ast as ast; -use rustc_attr::{ConstStability, StabilityLevel}; +use rustc_attr::{ConstStability, StabilityLevel, StableSince}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; @@ -1633,17 +1633,24 @@ impl PrintWithSpace for hir::Mutability { pub(crate) fn print_constness_with_space( c: &hir::Constness, - s: Option, + overall_stab: Option, + const_stab: Option, ) -> &'static str { - match (c, s) { - // const stable or when feature(staged_api) is not set - ( - hir::Constness::Const, - Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }), - ) - | (hir::Constness::Const, None) => "const ", - // const unstable or not const - _ => "", + match c { + hir::Constness::Const => match (overall_stab, const_stab) { + // const stable... + (_, Some(ConstStability { level: StabilityLevel::Stable { .. }, .. })) + // ...or when feature(staged_api) is not set... + | (_, None) + // ...or when const unstable, but overall unstable too + | (None, Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. })) => { + "const " + } + // const unstable (and overall stable) + (Some(_), Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. })) => "", + }, + // not const + hir::Constness::NotConst => "", } } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index f3ae4b76883e..8ee4cc5c75e4 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -928,9 +928,11 @@ fn assoc_method( // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove // this condition. let constness = match render_mode { - RenderMode::Normal => { - print_constness_with_space(&header.constness, meth.const_stability(tcx)) - } + RenderMode::Normal => print_constness_with_space( + &header.constness, + meth.stable_since(tcx), + meth.const_stability(tcx), + ), RenderMode::ForDeref { .. } => "", }; let asyncness = header.asyncness.print_with_space(); @@ -1016,18 +1018,23 @@ fn render_stability_since_raw_with_extra( .map(|since| (format!("const since {since}"), format!("const: {since}"))) } Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => { - let unstable = if let Some(n) = issue { - format!( - "unstable" - ) - } else { - String::from("unstable") - }; + ) + } else { + String::from("unstable") + }; - Some((String::from("const unstable"), format!("const: {unstable}"))) + Some((String::from("const unstable"), format!("const: {unstable}"))) + } } _ => None, }; diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index c7a23aa8503a..c5b88c7a951f 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -615,7 +615,18 @@ fn extra_info_tags<'a, 'tcx: 'a>( fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &clean::Function) { let tcx = cx.tcx(); let header = it.fn_header(tcx).expect("printing a function which isn't a function"); - let constness = print_constness_with_space(&header.constness, it.const_stability(tcx)); + debug!( + "item_function/const: {:?} {:?} {:?} {:?}", + it.name, + &header.constness, + it.stable_since(tcx), + it.const_stability(tcx), + ); + let constness = print_constness_with_space( + &header.constness, + it.stable_since(tcx), + it.const_stability(tcx), + ); let safety = header.safety.print_with_space(); let abi = print_abi_with_space(header.abi).to_string(); let asyncness = header.asyncness.print_with_space(); diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 22ab576b0776..c79b377727ab 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -441,10 +441,19 @@ impl<'a> LintExtractor<'a> { fs::write(&tempfile, source) .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?; let mut cmd = Command::new(self.rustc_path); - if options.contains(&"edition2015") { - cmd.arg("--edition=2015"); - } else { + if options.contains(&"edition2024") { + cmd.arg("--edition=2024"); + } else if options.contains(&"edition2021") { + cmd.arg("--edition=2021"); + } else if options.contains(&"edition2018") { cmd.arg("--edition=2018"); + } else if options.contains(&"edition2015") { + cmd.arg("--edition=2015"); + } else if options.contains(&"edition") { + panic!("lint-docs: unknown edition"); + } else { + // defaults to latest edition + cmd.arg("--edition=2021"); } cmd.arg("--error-format=json"); cmd.arg("--target").arg(self.rustc_target); diff --git a/src/tools/miri/tests/panic/mir-validation.stderr b/src/tools/miri/tests/panic/mir-validation.stderr index d5dd53d7b4e9..534e2d5881ff 100644 --- a/src/tools/miri/tests/panic/mir-validation.stderr +++ b/src/tools/miri/tests/panic/mir-validation.stderr @@ -1,6 +1,6 @@ thread 'rustc' panicked at compiler/rustc_mir_transform/src/validate.rs:LL:CC: broken MIR in Item(DefId) (after phase change to runtime-optimized) at bb0[1]: -(*(_2.0: *mut i32)), has deref at the wrong place +place (*(_2.0: *mut i32)) has deref as a later projection (it is only permitted as the first projection) stack backtrace: error: the compiler unexpectedly panicked. this is a bug. diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs index 332126939c08..d864ddf4eb17 100644 --- a/src/tools/run-make-support/src/diff/mod.rs +++ b/src/tools/run-make-support/src/diff/mod.rs @@ -51,7 +51,10 @@ impl Diff { /// Specify the actual output for the diff from a file. pub fn actual_file>(&mut self, path: P) -> &mut Self { let path = path.as_ref(); - let content = std::fs::read_to_string(path).expect("failed to read file"); + let content = match std::fs::read_to_string(path) { + Ok(c) => c, + Err(e) => panic!("failed to read `{}`: {:?}", path.display(), e), + }; let name = path.to_string_lossy().to_string(); self.actual = Some(content); diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 9854d91e19e3..d96c8b891278 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -12,6 +12,8 @@ pub mod rustc; pub mod rustdoc; use std::env; +use std::fs; +use std::io; use std::path::{Path, PathBuf}; use std::process::{Command, Output}; @@ -201,6 +203,71 @@ pub fn set_host_rpath(cmd: &mut Command) { }); } +/// Copy a directory into another. +pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) { + fn copy_dir_all_inner(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { + let dst = dst.as_ref(); + if !dst.is_dir() { + fs::create_dir_all(&dst)?; + } + for entry in fs::read_dir(src)? { + let entry = entry?; + let ty = entry.file_type()?; + if ty.is_dir() { + copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?; + } else { + fs::copy(entry.path(), dst.join(entry.file_name()))?; + } + } + Ok(()) + } + + if let Err(e) = copy_dir_all_inner(&src, &dst) { + // Trying to give more context about what exactly caused the failure + panic!( + "failed to copy `{}` to `{}`: {:?}", + src.as_ref().display(), + dst.as_ref().display(), + e + ); + } +} + +/// Check that all files in `dir1` exist and have the same content in `dir2`. Panic otherwise. +pub fn recursive_diff(dir1: impl AsRef, dir2: impl AsRef) { + fn read_file(path: &Path) -> Vec { + match fs::read(path) { + Ok(c) => c, + Err(e) => panic!("Failed to read `{}`: {:?}", path.display(), e), + } + } + + let dir2 = dir2.as_ref(); + for entry in fs::read_dir(dir1).unwrap() { + let entry = entry.unwrap(); + let entry_name = entry.file_name(); + let path = entry.path(); + + if path.is_dir() { + recursive_diff(&path, &dir2.join(entry_name)); + } else { + let path2 = dir2.join(entry_name); + let file1 = read_file(&path); + let file2 = read_file(&path2); + + // We don't use `assert_eq!` because they are `Vec`, so not great for display. + // Why not using String? Because there might be minified files or even potentially + // binary ones, so that would display useless output. + assert!( + file1 == file2, + "`{}` and `{}` have different content", + path.display(), + path2.display(), + ); + } + } +} + /// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct /// containing a `cmd: Command` field and a `output` function. The provided helpers are: /// diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs index c4f4e9f9bd23..9c77f1ca4624 100644 --- a/src/tools/run-make-support/src/rustdoc.rs +++ b/src/tools/run-make-support/src/rustdoc.rs @@ -151,6 +151,13 @@ impl Rustdoc { self } + /// Specify the output format. + pub fn output_format(&mut self, format: &str) -> &mut Self { + self.cmd.arg("--output-format"); + self.cmd.arg(format); + self + } + #[track_caller] pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output { let caller_location = std::panic::Location::caller(); diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 9a6ae18abead..2329b8b44dea 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -18,7 +18,6 @@ run-make/cdylib-fewer-symbols/Makefile run-make/cdylib/Makefile run-make/codegen-options-parsing/Makefile run-make/comment-section/Makefile -run-make/compile-stdin/Makefile run-make/compiler-lookup-paths-2/Makefile run-make/compiler-lookup-paths/Makefile run-make/compiler-rt-works-on-mingw/Makefile @@ -227,7 +226,6 @@ run-make/rlib-format-packed-bundled-libs/Makefile run-make/rmeta-preferred/Makefile run-make/rustc-macro-dep-files/Makefile run-make/rustdoc-io-error/Makefile -run-make/rustdoc-verify-output-files/Makefile run-make/sanitizer-cdylib-link/Makefile run-make/sanitizer-dylib-link/Makefile run-make/sanitizer-staticlib-link/Makefile diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 37324639edfc..055d620361fb 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -12,10 +12,10 @@ use std::path::{Path, PathBuf}; // should all be 1000 or lower. Limits significantly smaller than 1000 are also // desirable, because large numbers of files are unwieldy in general. See issue // #73494. -const ENTRY_LIMIT: usize = 900; +const ENTRY_LIMIT: u32 = 900; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: usize = 1676; +const ISSUES_ENTRY_LIMIT: u32 = 1676; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files @@ -53,7 +53,7 @@ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[ ]; fn check_entries(tests_path: &Path, bad: &mut bool) { - let mut directories: HashMap = HashMap::new(); + let mut directories: HashMap = HashMap::new(); for dir in Walk::new(&tests_path.join("ui")) { if let Ok(entry) = dir { @@ -62,7 +62,7 @@ fn check_entries(tests_path: &Path, bad: &mut bool) { } } - let (mut max, mut max_issues) = (0usize, 0usize); + let (mut max, mut max_issues) = (0, 0); for (dir_path, count) in directories { let is_issues_dir = tests_path.join("ui/issues") == dir_path; let (limit, maxcnt) = if is_issues_dir { diff --git a/tests/crashes/123255.rs b/tests/crashes/123255.rs new file mode 100644 index 000000000000..a94a2a0422e7 --- /dev/null +++ b/tests/crashes/123255.rs @@ -0,0 +1,13 @@ +//@ known-bug: rust-lang/rust#123255 +//@ edition:2021 +#![crate_type = "lib"] + +pub fn a() {} + +mod handlers { + pub struct C(&()); + pub fn c() -> impl Fn() -> C { + let a1 = (); + || C((crate::a(), a1).into()) + } +} diff --git a/tests/crashes/123276.rs b/tests/crashes/123276.rs new file mode 100644 index 000000000000..d2246f595838 --- /dev/null +++ b/tests/crashes/123276.rs @@ -0,0 +1,25 @@ +//@ known-bug: rust-lang/rust#123276 +//@ edition:2021 + +async fn create_task() { + _ = Some(async { bind(documentation_filter()) }); +} + +async fn bind>(_: F) {} + +fn documentation_filter() -> impl Filter { + AndThen +} + +trait Filter { + type Future; +} + +struct AndThen; + +impl Filter for AndThen +where + Foo: Filter, +{ + type Future = (); +} diff --git a/tests/crashes/123887.rs b/tests/crashes/123887.rs new file mode 100644 index 000000000000..68e2fb0325c3 --- /dev/null +++ b/tests/crashes/123887.rs @@ -0,0 +1,15 @@ +//@ known-bug: rust-lang/rust#123887 +//@ compile-flags: -Clink-dead-code + +#![feature(extern_types)] +#![feature(unsized_fn_params)] + +extern "C" { + pub type ExternType; +} + +impl ExternType { + pub fn f(self) {} +} + +pub fn main() {} diff --git a/tests/crashes/125013-1.rs b/tests/crashes/125013-1.rs new file mode 100644 index 000000000000..ae66d7a14669 --- /dev/null +++ b/tests/crashes/125013-1.rs @@ -0,0 +1,5 @@ +//@ known-bug: rust-lang/rust#125013 +//@ edition:2021 +use io::{self as std}; +use std::ops::Deref::{self as io}; +pub fn main() {} diff --git a/tests/crashes/125013-2.rs b/tests/crashes/125013-2.rs new file mode 100644 index 000000000000..a14c8a76b63e --- /dev/null +++ b/tests/crashes/125013-2.rs @@ -0,0 +1,16 @@ +//@ known-bug: rust-lang/rust#125013 +//@ edition:2021 +mod a { + pub mod b { + pub mod c { + pub trait D {} + } + } +} + +use a::*; + +use e as b; +use b::c::D as e; + +fn main() { } diff --git a/tests/crashes/125014.rs b/tests/crashes/125014.rs new file mode 100644 index 000000000000..b29042ee5983 --- /dev/null +++ b/tests/crashes/125014.rs @@ -0,0 +1,17 @@ +//@ known-bug: rust-lang/rust#125014 +//@ compile-flags: -Znext-solver=coherence +#![feature(specialization)] + +trait Foo {} + +impl Foo for ::Output {} + +impl Foo for u32 {} + +trait Assoc { + type Output; +} +impl Output for u32 {} +impl Assoc for ::Output { + default type Output = bool; +} diff --git a/tests/crashes/125059.rs b/tests/crashes/125059.rs new file mode 100644 index 000000000000..7e9f7414816e --- /dev/null +++ b/tests/crashes/125059.rs @@ -0,0 +1,12 @@ +//@ known-bug: rust-lang/rust#125059 +#![feature(deref_patterns)] +#![allow(incomplete_features)] + +fn simple_vec(vec: Vec) -> u32 { + (|| match Vec::::new() { + deref!([]) => 100, + _ => 2000, + })() +} + +fn main() {} diff --git a/tests/crashes/125323.rs b/tests/crashes/125323.rs new file mode 100644 index 000000000000..180b7bbad097 --- /dev/null +++ b/tests/crashes/125323.rs @@ -0,0 +1,6 @@ +//@ known-bug: rust-lang/rust#125323 +fn main() { + for _ in 0..0 { + [(); loop {}]; + } +} diff --git a/tests/crashes/125476.rs b/tests/crashes/125476.rs new file mode 100644 index 000000000000..aa9a081388d9 --- /dev/null +++ b/tests/crashes/125476.rs @@ -0,0 +1,4 @@ +//@ known-bug: rust-lang/rust#125476 +//@ only-x86_64 +pub struct Data([u8; usize::MAX >> 16]); +const _: &'static [Data] = &[]; diff --git a/tests/crashes/125512.rs b/tests/crashes/125512.rs new file mode 100644 index 000000000000..1672b24a1143 --- /dev/null +++ b/tests/crashes/125512.rs @@ -0,0 +1,10 @@ +//@ known-bug: rust-lang/rust#125512 +//@ edition:2021 +#![feature(object_safe_for_dispatch)] +trait B { + fn f(a: A) -> A; +} +trait A { + fn concrete(b: B) -> B; +} +fn main() {} diff --git a/tests/crashes/125553.rs b/tests/crashes/125553.rs new file mode 100644 index 000000000000..142c06775bb8 --- /dev/null +++ b/tests/crashes/125553.rs @@ -0,0 +1,15 @@ +//@ known-bug: rust-lang/rust#125553 +//@ edition:2021 + +#[derive(Copy, Clone)] +struct Foo((u32, u32)); + +fn main() { + type T = impl Copy(Copy, Clone) + let foo: T = Foo((1u32, 1u32)); + let x = move || { + let derive = move || { + let Foo((a, b)) = foo; + }; + }; +} diff --git a/tests/crashes/125556.rs b/tests/crashes/125556.rs new file mode 100644 index 000000000000..f2e2a991b11e --- /dev/null +++ b/tests/crashes/125556.rs @@ -0,0 +1,14 @@ +//@ known-bug: rust-lang/rust#125556 +//@ compile-flags: -Znext-solver=coherence + +#![feature(generic_const_exprs)] + +pub struct A {} + +impl A<2> { + pub const fn B() {} +} + +impl A<2> { + pub const fn B() {} +} diff --git a/tests/run-make/compile-stdin/Makefile b/tests/run-make/compile-stdin/Makefile deleted file mode 100644 index b3d7cc777a01..000000000000 --- a/tests/run-make/compile-stdin/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# When provided standard input piped directly into rustc, this test checks that the compilation completes successfully and that the output can be executed. -# See https://github.com/rust-lang/rust/pull/28805 - -# ignore-cross-compile -include ../tools.mk - -all: - echo 'fn main(){}' | $(RUSTC) - - $(call RUN,rust_out) diff --git a/tests/run-make/compile-stdin/rmake.rs b/tests/run-make/compile-stdin/rmake.rs new file mode 100644 index 000000000000..f93080dfdc4f --- /dev/null +++ b/tests/run-make/compile-stdin/rmake.rs @@ -0,0 +1,13 @@ +// When provided standard input piped directly into rustc, this test checks that the compilation +// completes successfully and that the output can be executed. +// +// See . + +//@ ignore-cross-compile + +use run_make_support::{run, rustc}; + +fn main() { + rustc().arg("-").stdin("fn main() {}").run(); + run("rust_out"); +} diff --git a/tests/run-make/rustdoc-verify-output-files/Makefile b/tests/run-make/rustdoc-verify-output-files/Makefile deleted file mode 100644 index 76f233ab445d..000000000000 --- a/tests/run-make/rustdoc-verify-output-files/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -include ../tools.mk - -OUTPUT_DIR := "$(TMPDIR)/rustdoc" -TMP_OUTPUT_DIR := "$(TMPDIR)/tmp-rustdoc" - -all: - # Generate html docs - $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR) - - # Copy first output for to check if it's exactly same after second compilation - cp -R $(OUTPUT_DIR) $(TMP_OUTPUT_DIR) - - # Generate html docs once again on same output - $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR) - - # Check if everything exactly same - $(DIFF) -r $(OUTPUT_DIR) $(TMP_OUTPUT_DIR) - - # Generate json doc on the same output - $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR) -Z unstable-options --output-format json - - # Check if expected json file is generated - [ -e $(OUTPUT_DIR)/foobar.json ] - - # Copy first json output to check if it's exactly same after second compilation - cp -R $(OUTPUT_DIR)/foobar.json $(TMP_OUTPUT_DIR)/foobar.json - - # Generate json doc on the same output - $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR) -Z unstable-options --output-format json - - # Check if all docs(including both json and html formats) are still the same after multiple compilations - $(DIFF) -r $(OUTPUT_DIR) $(TMP_OUTPUT_DIR) diff --git a/tests/run-make/rustdoc-verify-output-files/rmake.rs b/tests/run-make/rustdoc-verify-output-files/rmake.rs new file mode 100644 index 000000000000..212e7eaba2d6 --- /dev/null +++ b/tests/run-make/rustdoc-verify-output-files/rmake.rs @@ -0,0 +1,49 @@ +use std::fs::copy; +use std::path::{Path, PathBuf}; + +use run_make_support::{copy_dir_all, recursive_diff, rustdoc, tmp_dir}; + +#[derive(PartialEq)] +enum JsonOutput { + Yes, + No, +} + +fn generate_docs(out_dir: &Path, json_output: JsonOutput) { + let mut rustdoc = rustdoc(); + rustdoc.input("src/lib.rs").crate_name("foobar").crate_type("lib").out_dir(&out_dir); + if json_output == JsonOutput::Yes { + rustdoc.arg("-Zunstable-options").output_format("json"); + } + rustdoc.run(); +} + +fn main() { + let out_dir = tmp_dir().join("rustdoc"); + let tmp_out_dir = tmp_dir().join("tmp-rustdoc"); + + // Generate HTML docs. + generate_docs(&out_dir, JsonOutput::No); + + // Copy first output for to check if it's exactly same after second compilation. + copy_dir_all(&out_dir, &tmp_out_dir); + + // Generate html docs once again on same output. + generate_docs(&out_dir, JsonOutput::No); + + // Generate json doc on the same output. + generate_docs(&out_dir, JsonOutput::Yes); + + // Check if expected json file is generated. + assert!(out_dir.join("foobar.json").is_file()); + + // Copy first json output to check if it's exactly same after second compilation. + copy(out_dir.join("foobar.json"), tmp_out_dir.join("foobar.json")).unwrap(); + + // Generate json doc on the same output. + generate_docs(&out_dir, JsonOutput::Yes); + + // Check if all docs(including both json and html formats) are still the same after multiple + // compilations. + recursive_diff(&out_dir, &tmp_out_dir); +} diff --git a/tests/rustdoc/const-display.rs b/tests/rustdoc/const-display.rs index c8967f426f0a..959a00102b7e 100644 --- a/tests/rustdoc/const-display.rs +++ b/tests/rustdoc/const-display.rs @@ -24,6 +24,12 @@ pub const unsafe fn foo_unsafe() -> u32 { 42 } #[unstable(feature = "humans", issue = "none")] pub const fn foo2() -> u32 { 42 } +// @has 'foo/fn.foo3.html' '//pre' 'pub const fn foo3() -> u32' +// @!hasraw - '//span[@class="since"]' +#[unstable(feature = "humans", issue = "none")] +#[rustc_const_unstable(feature = "humans", issue = "none")] +pub const fn foo3() -> u32 { 42 } + // @has 'foo/fn.bar2.html' '//pre' 'pub const fn bar2() -> u32' // @has - //span '1.0.0 (const: 1.0.0)' #[stable(feature = "rust1", since = "1.0.0")] diff --git a/tests/ui/const-generics/generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.rs b/tests/ui/const-generics/generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.rs new file mode 100644 index 000000000000..cd2dc3f4fe85 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.rs @@ -0,0 +1,27 @@ +// issue: rust-lang/rust#125520 +#![feature(generic_const_exprs)] +//~^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + +struct Outer(); +impl Outer +//~^ ERROR the constant `A` is not of type `i64` +//~| ERROR the constant `B` is not of type `i64` +//~| ERROR mismatched types +//~| ERROR mismatched types +where + [(); A + (B * 2)]:, +{ + fn i() -> Self { + //~^ ERROR the constant `A` is not of type `i64` + //~| ERROR the constant `B` is not of type `i64` + Self + //~^ ERROR mismatched types + //~| ERROR the constant `A` is not of type `i64` + //~| ERROR the constant `B` is not of type `i64` + } +} + +fn main() { + Outer::<1, 1>::o(); + //~^ ERROR no function or associated item named `o` found for struct `Outer` in the current scope +} diff --git a/tests/ui/const-generics/generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.stderr b/tests/ui/const-generics/generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.stderr new file mode 100644 index 000000000000..2dbd69fd3bc1 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.stderr @@ -0,0 +1,125 @@ +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:2:12 + | +LL | #![feature(generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: the constant `A` is not of type `i64` + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:6:38 + | +LL | impl Outer + | ^^^^^^^^^^^ expected `i64`, found `usize` + | +note: required by a bound in `Outer` + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:14 + | +LL | struct Outer(); + | ^^^^^^^^^^^^ required by this bound in `Outer` + +error: the constant `B` is not of type `i64` + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:6:38 + | +LL | impl Outer + | ^^^^^^^^^^^ expected `i64`, found `usize` + | +note: required by a bound in `Outer` + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:28 + | +LL | struct Outer(); + | ^^^^^^^^^^^^ required by this bound in `Outer` + +error: the constant `A` is not of type `i64` + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:14:15 + | +LL | fn i() -> Self { + | ^^^^ expected `i64`, found `usize` + | +note: required by a bound in `Outer` + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:14 + | +LL | struct Outer(); + | ^^^^^^^^^^^^ required by this bound in `Outer` + +error: the constant `B` is not of type `i64` + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:14:15 + | +LL | fn i() -> Self { + | ^^^^ expected `i64`, found `usize` + | +note: required by a bound in `Outer` + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:28 + | +LL | struct Outer(); + | ^^^^^^^^^^^^ required by this bound in `Outer` + +error[E0308]: mismatched types + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:17:9 + | +LL | struct Outer(); + | ---------------------------------------- `Outer` defines a struct constructor here, which should be called +... +LL | fn i() -> Self { + | ---- expected `Outer` because of return type +... +LL | Self + | ^^^^ expected `Outer`, found struct constructor + | + = note: expected struct `Outer` + found struct constructor `fn() -> Outer {Outer::}` +help: use parentheses to construct this tuple struct + | +LL | Self() + | ++ + +error: the constant `A` is not of type `i64` + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:17:9 + | +LL | Self + | ^^^^ expected `i64`, found `usize` + | +note: required by a bound in `Outer` + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:14 + | +LL | struct Outer(); + | ^^^^^^^^^^^^ required by this bound in `Outer` + +error: the constant `B` is not of type `i64` + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:17:9 + | +LL | Self + | ^^^^ expected `i64`, found `usize` + | +note: required by a bound in `Outer` + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:28 + | +LL | struct Outer(); + | ^^^^^^^^^^^^ required by this bound in `Outer` + +error[E0599]: no function or associated item named `o` found for struct `Outer` in the current scope + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:25:20 + | +LL | struct Outer(); + | ---------------------------------------- function or associated item `o` not found for this struct +... +LL | Outer::<1, 1>::o(); + | ^ function or associated item not found in `Outer<1, 1>` + +error[E0308]: mismatched types + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:6:44 + | +LL | impl Outer + | ^ expected `i64`, found `usize` + +error[E0308]: mismatched types + --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:6:47 + | +LL | impl Outer + | ^ expected `i64`, found `usize` + +error: aborting due to 10 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0308, E0599. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/issues/issue-105821.rs b/tests/ui/const-generics/issues/issue-105821.rs index 282cbe9249d9..e55da461605e 100644 --- a/tests/ui/const-generics/issues/issue-105821.rs +++ b/tests/ui/const-generics/issues/issue-105821.rs @@ -1,5 +1,5 @@ //@ failure-status: 101 -//@ known-bug: unknown +//@ known-bug: rust-lang/rust#125451 //@ normalize-stderr-test "note: .*\n\n" -> "" //@ normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> "" //@ normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs new file mode 100644 index 000000000000..beda719ac208 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs @@ -0,0 +1,28 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// The new trait solver does not return region constraints if the goal +// is still ambiguous. This causes the following test to fail with ambiguity, +// even though `(): LeakCheckFailure<'!a, V>` would return `'!a: 'static` +// which would have caused a leak check failure. + +trait Ambig {} +impl Ambig for u32 {} +impl Ambig for u16 {} + +trait Id {} +impl Id for u32 {} +impl Id for u16 {} + + +trait LeakCheckFailure<'a, V: ?Sized> {} +impl LeakCheckFailure<'static, V> for () {} + +trait Trait {} +impl Trait for () where for<'a> (): LeakCheckFailure<'a, V> {} +impl Trait for () {} +fn impls_trait, U: Id, V>() {} +fn main() { + impls_trait::<(), _, _>() +} diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.next.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.next.stderr new file mode 100644 index 000000000000..a12e3312230a --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.next.stderr @@ -0,0 +1,22 @@ +error[E0283]: type annotations needed + --> $DIR/leak-check-in-selection-6-ambig-unify.rs:30:5 + | +LL | impls_trait::<(), _, _>() + | ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait` + | +note: multiple `impl`s satisfying `(): Trait<_, _>` found + --> $DIR/leak-check-in-selection-6-ambig-unify.rs:26:1 + | +LL | impl Trait for () where for<'b> (): LeakCheckFailure<'static, 'b, V> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Trait for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `impls_trait` + --> $DIR/leak-check-in-selection-6-ambig-unify.rs:28:19 + | +LL | fn impls_trait, U: Id, V>() {} + | ^^^^^^^^^^^ required by this bound in `impls_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.old.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.old.stderr new file mode 100644 index 000000000000..a12e3312230a --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.old.stderr @@ -0,0 +1,22 @@ +error[E0283]: type annotations needed + --> $DIR/leak-check-in-selection-6-ambig-unify.rs:30:5 + | +LL | impls_trait::<(), _, _>() + | ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait` + | +note: multiple `impl`s satisfying `(): Trait<_, _>` found + --> $DIR/leak-check-in-selection-6-ambig-unify.rs:26:1 + | +LL | impl Trait for () where for<'b> (): LeakCheckFailure<'static, 'b, V> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Trait for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `impls_trait` + --> $DIR/leak-check-in-selection-6-ambig-unify.rs:28:19 + | +LL | fn impls_trait, U: Id, V>() {} + | ^^^^^^^^^^^ required by this bound in `impls_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs new file mode 100644 index 000000000000..592d581695e5 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs @@ -0,0 +1,32 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver + +// The new trait solver does not return region constraints if the goal +// is still ambiguous. This should cause the following test to fail with +// ambiguity as even if `(): LeakCheckFailure<'static, '!b, V>` unifies +// `'!b` with `'static`, we erase all region constraints. +// +// However, we do still unify the var_value for `'b` with `'static`, +// causing us to return this requirement via the `var_values` even if +// we don't return any region constraints. This is a bit inconsistent +// but isn't something we should really worry about imo. +trait Ambig {} +impl Ambig for u32 {} +impl Ambig for u16 {} + +trait Id {} +impl Id for u32 {} +impl Id for u16 {} + + +trait LeakCheckFailure<'a, 'b, V: ?Sized> {} +impl<'a, 'b: 'a, V: ?Sized + Ambig> LeakCheckFailure<'a, 'b, V> for () {} + +trait Trait {} +impl Trait for () where for<'b> (): LeakCheckFailure<'static, 'b, V> {} +impl Trait for () {} +fn impls_trait, U: Id, V>() {} +fn main() { + impls_trait::<(), _, _>() + //~^ ERROR type annotations needed +} diff --git a/tests/ui/traits/next-solver/normalize/ambig-goal-infer-in-type-oulives.rs b/tests/ui/traits/next-solver/normalize/ambig-goal-infer-in-type-oulives.rs new file mode 100644 index 000000000000..18dc34f7cc43 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize/ambig-goal-infer-in-type-oulives.rs @@ -0,0 +1,29 @@ +//@ check-pass +//@ compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicitly enabled) + +// Regression test for an ICE when trying to bootstrap rustc +// with #125343. An ambiguous goal returned a `TypeOutlives` +// constraint referencing an inference variable. This inference +// variable was created inside of the goal, causing it to be +// unconstrained in the caller. This then caused an ICE in MIR +// borrowck. + +struct Foo(T); +trait Extend { + fn extend>(iter: I); +} + +impl Extend for Foo { + fn extend>(_: I) { + todo!() + } +} + +impl<'a, T: 'a + Copy> Extend<&'a T> for Foo { + fn extend>(iter: I) { + >::extend(iter.into_iter().copied()) + } +} + +fn main() {}