diff options
Diffstat (limited to 'compiler')
84 files changed, 1015 insertions, 868 deletions
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index d7767efa984..cd621bc67a1 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1567,8 +1567,18 @@ impl<'a> State<'a> { match bound { GenericBound::Trait(tref, modifier) => { - if modifier == &TraitBoundModifier::Maybe { - self.word("?"); + match modifier { + TraitBoundModifier::None => {} + TraitBoundModifier::Maybe => { + self.word("?"); + } + TraitBoundModifier::MaybeConst => { + self.word_space("~const"); + } + TraitBoundModifier::MaybeConstMaybe => { + self.word_space("~const"); + self.word("?"); + } } self.print_poly_trait_ref(tref); } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index b0a8188e5e0..7b07c2a4633 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -803,6 +803,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { predicates .iter() .map(|(param, constraint)| (param.name.as_str(), &**constraint, None)), + None, ); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index a75ec87be4c..3006e27e1d5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1139,7 +1139,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let ty::Adt(def, substs) = ty.kind() && Some(def.did()) == tcx.lang_items().pin_type() && let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind() - && let self_ty = infcx.replace_bound_vars_with_fresh_vars( + && let self_ty = infcx.instantiate_binder_with_fresh_vars( fn_call_span, LateBoundRegionConversionTime::FnCall, tcx.fn_sig(method_did).subst(tcx, method_substs).input(0), diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index e15d1b99ad2..1dc6c42fbf7 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -83,16 +83,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } self.constraints.member_constraints = tmp; - for (predicate, constraint_category) in outlives { - // At the moment, we never generate any "higher-ranked" - // region constraints like `for<'a> 'a: 'b`. At some point - // when we move to universes, we will, and this assertion - // will start to fail. - let predicate = predicate.no_bound_vars().unwrap_or_else(|| { - bug!("query_constraint {:?} contained bound vars", predicate,); - }); - - self.convert(predicate, *constraint_category); + for &(predicate, constraint_category) in outlives { + self.convert(predicate, constraint_category); } } diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index fa9ea769a14..c6b78df9a5f 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -38,7 +38,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // so that they represent the view from "inside" the closure. let user_provided_sig = self .instantiate_canonical_with_fresh_inference_vars(body.span, &user_provided_poly_sig); - let user_provided_sig = self.infcx.replace_bound_vars_with_fresh_vars( + let user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars( body.span, LateBoundRegionConversionTime::FnCall, user_provided_sig, diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 74e2597830e..e8a353b1c8f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -153,7 +153,10 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> let path_debug = cx.path_global(span, cx.std_path(&[sym::fmt, sym::Debug])); let ty_dyn_debug = cx.ty( span, - ast::TyKind::TraitObject(vec![cx.trait_bound(path_debug)], ast::TraitObjectSyntax::Dyn), + ast::TyKind::TraitObject( + vec![cx.trait_bound(path_debug, false)], + ast::TraitObjectSyntax::Dyn, + ), ); let ty_slice = cx.ty( span, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 97de40bac34..970b9115d8d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -605,18 +605,26 @@ impl<'a> TraitDef<'a> { let bounds: Vec<_> = self .additional_bounds .iter() - .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) + .map(|p| { + cx.trait_bound( + p.to_path(cx, self.span, type_ident, generics), + self.is_const, + ) + }) .chain( // Add a bound for the current trait. self.skip_path_as_bound .not() - .then(|| cx.trait_bound(trait_path.clone())), + .then(|| cx.trait_bound(trait_path.clone(), self.is_const)), ) .chain({ // Add a `Copy` bound if required. if is_packed && self.needs_copy_as_bound_if_packed { let p = deriving::path_std!(marker::Copy); - Some(cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) + Some(cx.trait_bound( + p.to_path(cx, self.span, type_ident, generics), + self.is_const, + )) } else { None } @@ -694,18 +702,24 @@ impl<'a> TraitDef<'a> { let mut bounds: Vec<_> = self .additional_bounds .iter() - .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) + .map(|p| { + cx.trait_bound( + p.to_path(cx, self.span, type_ident, generics), + self.is_const, + ) + }) .collect(); // Require the current trait. - bounds.push(cx.trait_bound(trait_path.clone())); + bounds.push(cx.trait_bound(trait_path.clone(), self.is_const)); // Add a `Copy` bound if required. if is_packed && self.needs_copy_as_bound_if_packed { let p = deriving::path_std!(marker::Copy); - bounds.push( - cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)), - ); + bounds.push(cx.trait_bound( + p.to_path(cx, self.span, type_ident, generics), + self.is_const, + )); } let predicate = ast::WhereBoundPredicate { @@ -1543,31 +1557,46 @@ impl<'a> TraitDef<'a> { }), ), ); - // In general, fields in packed structs are copied via a - // block, e.g. `&{self.0}`. The one exception is `[u8]` - // fields, which cannot be copied and also never cause - // unaligned references. This exception is allowed to - // handle the `FlexZeroSlice` type in the `zerovec` crate - // within `icu4x-0.9.0`. - // - // Once use of `icu4x-0.9.0` has dropped sufficiently, this - // exception should be removed. - let is_u8_slice = if let TyKind::Slice(ty) = &struct_field.ty.kind && - let TyKind::Path(None, rustc_ast::Path { segments, .. }) = &ty.kind && - let [seg] = segments.as_slice() && - seg.ident.name == sym::u8 && seg.args.is_none() - { - true - } else { - false - }; if is_packed { - if is_u8_slice { + // In general, fields in packed structs are copied via a + // block, e.g. `&{self.0}`. The two exceptions are `[u8]` + // and `str` fields, which cannot be copied and also never + // cause unaligned references. These exceptions are allowed + // to handle the `FlexZeroSlice` type in the `zerovec` + // crate within `icu4x-0.9.0`. + // + // Once use of `icu4x-0.9.0` has dropped sufficiently, this + // exception should be removed. + let is_simple_path = |ty: &P<ast::Ty>, sym| { + if let TyKind::Path(None, ast::Path { segments, .. }) = &ty.kind && + let [seg] = segments.as_slice() && + seg.ident.name == sym && seg.args.is_none() + { + true + } else { + false + } + }; + + let exception = if let TyKind::Slice(ty) = &struct_field.ty.kind && + is_simple_path(ty, sym::u8) + { + Some("byte") + } else if is_simple_path(&struct_field.ty, sym::str) { + Some("string") + } else { + None + }; + + if let Some(ty) = exception { cx.sess.parse_sess.buffer_lint_with_diagnostic( BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, sp, ast::CRATE_NODE_ID, - "byte slice in a packed struct that derives a built-in trait", + &format!( + "{} slice in a packed struct that derives a built-in trait", + ty + ), rustc_lint_defs::BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive ); } else { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index c6f5f5d0807..aabd5b1f773 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -154,7 +154,7 @@ fn mk_ty_param( .iter() .map(|b| { let path = b.to_path(cx, span, self_ident, self_generics); - cx.trait_bound(path) + cx.trait_bound(path, false) }) .collect(); cx.typaram(span, Ident::new(name, span), bounds, None) diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index b2c847d3fd8..fc8e0c67ae0 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -126,7 +126,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let vtable = self.get_vtable_ptr(src.layout.ty, data.principal())?; let vtable = Scalar::from_maybe_pointer(vtable, self); let data = self.read_immediate(src)?.to_scalar(); - let _assert_pointer_sized = data.to_pointer(self)?; + let _assert_pointer_like = data.to_pointer(self)?; let val = Immediate::ScalarPair(data, vtable); self.write_immediate(val, dest)?; } else { diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs index 77c7b4bacb8..5042c6bac99 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs @@ -78,13 +78,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { col: u32, ) -> MPlaceTy<'tcx, M::Provenance> { let loc_details = &self.tcx.sess.opts.unstable_opts.location_detail; + // This can fail if rustc runs out of memory right here. Trying to emit an error would be + // pointless, since that would require allocating more memory than these short strings. let file = if loc_details.file { self.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not) + .unwrap() } else { // FIXME: This creates a new allocation each time. It might be preferable to // perform this allocation only once, and re-use the `MPlaceTy`. // See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398 - self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not) + self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not).unwrap() }; let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) }; let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) }; @@ -95,8 +98,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .bound_type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None)) .subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_erased.into()].iter())); let loc_layout = self.layout_of(loc_ty).unwrap(); - // This can fail if rustc runs out of memory right here. Trying to emit an error would be - // pointless, since that would require allocating more memory than a Location. let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap(); // Initialize fields. diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 76ed7b80f8d..d8087a36a7c 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -291,7 +291,7 @@ pub trait Machine<'mir, 'tcx>: Sized { fn adjust_alloc_base_pointer( ecx: &InterpCx<'mir, 'tcx, Self>, ptr: Pointer, - ) -> Pointer<Self::Provenance>; + ) -> InterpResult<'tcx, Pointer<Self::Provenance>>; /// "Int-to-pointer cast" fn ptr_from_addr_cast( @@ -505,8 +505,8 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { fn adjust_alloc_base_pointer( _ecx: &InterpCx<$mir, $tcx, Self>, ptr: Pointer<AllocId>, - ) -> Pointer<AllocId> { - ptr + ) -> InterpResult<$tcx, Pointer<AllocId>> { + Ok(ptr) } #[inline(always)] diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index a87ce0053e8..cfad930b1e5 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -171,7 +171,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => {} } // And we need to get the provenance. - Ok(M::adjust_alloc_base_pointer(self, ptr)) + M::adjust_alloc_base_pointer(self, ptr) } pub fn create_fn_alloc_ptr( @@ -200,8 +200,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { kind: MemoryKind<M::MemoryKind>, ) -> InterpResult<'tcx, Pointer<M::Provenance>> { let alloc = Allocation::uninit(size, align, M::PANIC_ON_ALLOC_FAIL)?; - // We can `unwrap` since `alloc` contains no pointers. - Ok(self.allocate_raw_ptr(alloc, kind).unwrap()) + self.allocate_raw_ptr(alloc, kind) } pub fn allocate_bytes_ptr( @@ -210,10 +209,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { align: Align, kind: MemoryKind<M::MemoryKind>, mutability: Mutability, - ) -> Pointer<M::Provenance> { + ) -> InterpResult<'tcx, Pointer<M::Provenance>> { let alloc = Allocation::from_bytes(bytes, align, mutability); - // We can `unwrap` since `alloc` contains no pointers. - self.allocate_raw_ptr(alloc, kind).unwrap() + self.allocate_raw_ptr(alloc, kind) } /// This can fail only of `alloc` contains provenance. @@ -230,7 +228,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ); let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?; self.memory.alloc_map.insert(id, (kind, alloc.into_owned())); - Ok(M::adjust_alloc_base_pointer(self, Pointer::from(id))) + M::adjust_alloc_base_pointer(self, Pointer::from(id)) } pub fn reallocate_ptr( diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index f82a41078d1..038282e2161 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -754,8 +754,8 @@ where str: &str, kind: MemoryKind<M::MemoryKind>, mutbl: Mutability, - ) -> MPlaceTy<'tcx, M::Provenance> { - let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl); + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { + let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)?; let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self); let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) }; @@ -764,7 +764,7 @@ where ty::TypeAndMut { ty: self.tcx.types.str_, mutbl }, ); let layout = self.layout_of(ty).unwrap(); - MPlaceTy { mplace, layout, align: layout.align.abi } + Ok(MPlaceTy { mplace, layout, align: layout.align.abi }) } /// Writes the aggregate to the destination. diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 782a62accad..3e416b89ca6 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -136,6 +136,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { ¶m_ty.name.as_str(), &constraint, None, + None, ); } } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 954e84c303b..7fab8954cb1 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -11,6 +11,7 @@ #![feature(associated_type_bounds)] #![feature(auto_traits)] #![feature(cell_leak)] +#![feature(core_intrinsics)] #![feature(extend_one)] #![feature(hash_raw_entry)] #![feature(hasher_prefixfree_extras)] diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 393f1739081..3aca03f6e5c 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -88,6 +88,7 @@ use std::borrow::Borrow; use std::collections::hash_map::Entry; use std::error::Error; use std::fs; +use std::intrinsics::unlikely; use std::path::Path; use std::process; use std::sync::Arc; @@ -395,11 +396,18 @@ impl SelfProfilerRef { /// Record a query in-memory cache hit. #[inline(always)] pub fn query_cache_hit(&self, query_invocation_id: QueryInvocationId) { - self.instant_query_event( - |profiler| profiler.query_cache_hit_event_kind, - query_invocation_id, - EventFilter::QUERY_CACHE_HITS, - ); + #[inline(never)] + #[cold] + fn cold_call(profiler_ref: &SelfProfilerRef, query_invocation_id: QueryInvocationId) { + profiler_ref.instant_query_event( + |profiler| profiler.query_cache_hit_event_kind, + query_invocation_id, + ); + } + + if unlikely(self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS)) { + cold_call(self, query_invocation_id); + } } /// Start profiling a query being blocked on a concurrent execution. @@ -444,20 +452,15 @@ impl SelfProfilerRef { &self, event_kind: fn(&SelfProfiler) -> StringId, query_invocation_id: QueryInvocationId, - event_filter: EventFilter, ) { - drop(self.exec(event_filter, |profiler| { - let event_id = StringId::new_virtual(query_invocation_id.0); - let thread_id = get_thread_id(); - - profiler.profiler.record_instant_event( - event_kind(profiler), - EventId::from_virtual(event_id), - thread_id, - ); - - TimingGuard::none() - })); + let event_id = StringId::new_virtual(query_invocation_id.0); + let thread_id = get_thread_id(); + let profiler = self.profiler.as_ref().unwrap(); + profiler.profiler.record_instant_event( + event_kind(profiler), + EventId::from_virtual(event_id), + thread_id, + ); } pub fn with_profiler(&self, f: impl FnOnce(&SelfProfiler)) { diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 02e0b042ad2..bdf2978cee2 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -229,10 +229,6 @@ fn run_compiler( registry: diagnostics_registry(), }; - if !tracing::dispatcher::has_been_set() { - init_rustc_env_logger_with_backtrace_option(&config.opts.unstable_opts.log_backtrace); - } - match make_input(config.opts.error_format, &matches.free) { Err(reported) => return Err(reported), Ok(Some(input)) => { @@ -326,14 +322,16 @@ fn run_compiler( } } - let mut gctxt = queries.global_ctxt()?; + // Make sure name resolution and macro expansion is run. + queries.global_ctxt()?; + if callbacks.after_expansion(compiler, queries) == Compilation::Stop { return early_exit(); } // Make sure the `output_filenames` query is run for its side // effects of writing the dep-info and reporting errors. - gctxt.enter(|tcx| tcx.output_filenames(())); + queries.global_ctxt()?.enter(|tcx| tcx.output_filenames(())); if sess.opts.output_types.contains_key(&OutputType::DepInfo) && sess.opts.output_types.len() == 1 @@ -345,7 +343,7 @@ fn run_compiler( return early_exit(); } - gctxt.enter(|tcx| { + queries.global_ctxt()?.enter(|tcx| { let result = tcx.analysis(()); if sess.opts.unstable_opts.save_analysis { let crate_name = tcx.crate_name(LOCAL_CRATE); @@ -362,8 +360,6 @@ fn run_compiler( result })?; - drop(gctxt); - if callbacks.after_analysis(compiler, queries) == Compilation::Stop { return early_exit(); } @@ -1200,11 +1196,9 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { if !info.payload().is::<rustc_errors::ExplicitBug>() && !info.payload().is::<rustc_errors::DelayedBugPanic>() { - let mut d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic"); - handler.emit_diagnostic(&mut d); + handler.emit_err(session_diagnostics::Ice); } - handler.emit_note(session_diagnostics::Ice); handler.emit_note(session_diagnostics::IceBugReport { bug_report_url }); handler.emit_note(session_diagnostics::IceVersion { version: util::version_str!().unwrap_or("unknown_version"), @@ -1253,16 +1247,7 @@ pub fn install_ice_hook() { /// This allows tools to enable rust logging without having to magically match rustc's /// tracing crate version. pub fn init_rustc_env_logger() { - init_rustc_env_logger_with_backtrace_option(&None); -} - -/// This allows tools to enable rust logging without having to magically match rustc's -/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to -/// choose a target module you wish to show backtraces along with its logging. -pub fn init_rustc_env_logger_with_backtrace_option(backtrace_target: &Option<String>) { - if let Err(error) = rustc_log::init_rustc_env_logger_with_backtrace_option(backtrace_target) { - early_error(ErrorOutputType::default(), &error.to_string()); - } + init_env_logger("RUSTC_LOG"); } /// This allows tools to enable rust logging without having to magically match rustc's @@ -1326,6 +1311,7 @@ mod signal_handler { pub fn main() -> ! { let start_time = Instant::now(); let start_rss = get_resident_set_size(); + init_rustc_env_logger(); signal_handler::install(); let mut callbacks = TimePassesCallbacks::default(); install_ice_hook(); diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 072b0f2fcce..800f3c52177 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -286,6 +286,7 @@ E0519: include_str!("./error_codes/E0519.md"), E0520: include_str!("./error_codes/E0520.md"), E0521: include_str!("./error_codes/E0521.md"), E0522: include_str!("./error_codes/E0522.md"), +E0523: include_str!("./error_codes/E0523.md"), E0524: include_str!("./error_codes/E0524.md"), E0525: include_str!("./error_codes/E0525.md"), E0527: include_str!("./error_codes/E0527.md"), @@ -622,7 +623,6 @@ E0793: include_str!("./error_codes/E0793.md"), // E0488, // lifetime of variable does not enclose its declaration // E0489, // type/lifetime parameter not in scope here // E0490, // removed: unreachable - E0523, // two dependencies have same (crate-name, disambiguator) but different SVH // E0526, // shuffle indices are not constant // E0540, // multiple rustc_deprecated attributes // E0548, // replaced with a generic attribute input check diff --git a/compiler/rustc_error_codes/src/error_codes/E0464.md b/compiler/rustc_error_codes/src/error_codes/E0464.md index 9108d856c9d..209cbb00db5 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0464.md +++ b/compiler/rustc_error_codes/src/error_codes/E0464.md @@ -1,6 +1,21 @@ The compiler found multiple library files with the requested crate name. +```compile_fail +// aux-build:crateresolve-1.rs +// aux-build:crateresolve-2.rs +// aux-build:crateresolve-3.rs + +extern crate crateresolve; +//~^ ERROR multiple candidates for `rlib` dependency `crateresolve` found + +fn main() {} +``` + This error can occur in several different cases -- for example, when using `extern crate` or passing `--extern` options without crate paths. It can also be caused by caching issues with the build directory, in which case `cargo clean` may help. + +In the above example, there are three different library files, all of which +define the same crate name. Without providing a full path, there is no way for +the compiler to know which crate it should use. diff --git a/compiler/rustc_error_codes/src/error_codes/E0523.md b/compiler/rustc_error_codes/src/error_codes/E0523.md new file mode 100644 index 00000000000..0ddf70386c2 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0523.md @@ -0,0 +1,25 @@ +#### Note: this error code is no longer emitted by the compiler. + +The compiler found multiple library files with the requested crate name. + +```compile_fail +// aux-build:crateresolve-1.rs +// aux-build:crateresolve-2.rs +// aux-build:crateresolve-3.rs + +extern crate crateresolve; +//~^ ERROR multiple candidates for `rlib` dependency `crateresolve` found + +fn main() {} +``` + +This error can occur in several different cases -- for example, when using +`extern crate` or passing `--extern` options without crate paths. It can also be +caused by caching issues with the build directory, in which case `cargo clean` +may help. + +In the above example, there are three different library files, all of which +define the same crate name. Without providing a full path, there is no way for +the compiler to know which crate it should use. + +*Note that E0523 has been merged into E0464.* diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index faeaa548619..9768526a2f4 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1882,9 +1882,8 @@ impl EmitterWriter { &mut buffer, &mut row_num, &Vec::new(), - p, + p + line_start, l, - line_start, show_code_change, max_line_num_len, &file_lines, @@ -1907,9 +1906,8 @@ impl EmitterWriter { &mut buffer, &mut row_num, &Vec::new(), - p, + p + line_start, l, - line_start, show_code_change, max_line_num_len, &file_lines, @@ -1925,9 +1923,8 @@ impl EmitterWriter { &mut buffer, &mut row_num, &Vec::new(), - p, + p + line_start, l, - line_start, show_code_change, max_line_num_len, &file_lines, @@ -1941,9 +1938,8 @@ impl EmitterWriter { &mut buffer, &mut row_num, highlight_parts, - line_pos, + line_pos + line_start, line, - line_start, show_code_change, max_line_num_len, &file_lines, @@ -2167,40 +2163,63 @@ impl EmitterWriter { buffer: &mut StyledBuffer, row_num: &mut usize, highlight_parts: &Vec<SubstitutionHighlight>, - line_pos: usize, - line: &str, - line_start: usize, + line_num: usize, + line_to_add: &str, show_code_change: DisplaySuggestion, max_line_num_len: usize, file_lines: &FileLines, is_multiline: bool, ) { - // Print the span column to avoid confusion - buffer.puts(*row_num, 0, &self.maybe_anonymized(line_start + line_pos), Style::LineNumber); if let DisplaySuggestion::Diff = show_code_change { - // Add the line number for both addition and removal to drive the point home. - // - // N - fn foo<A: T>(bar: A) { - // N + fn foo(bar: impl T) { - buffer.puts( - *row_num - 1, - 0, - &self.maybe_anonymized(line_start + line_pos), - Style::LineNumber, - ); - buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal); - buffer.puts( - *row_num - 1, - max_line_num_len + 3, - &normalize_whitespace( - &file_lines.file.get_line(file_lines.lines[line_pos].line_index).unwrap(), - ), - Style::NoStyle, - ); - buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); + // We need to print more than one line if the span we need to remove is multiline. + // For more info: https://github.com/rust-lang/rust/issues/92741 + let lines_to_remove = file_lines.lines.iter().take(file_lines.lines.len() - 1); + for (index, line_to_remove) in lines_to_remove.enumerate() { + buffer.puts( + *row_num - 1, + 0, + &self.maybe_anonymized(line_num + index), + Style::LineNumber, + ); + buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal); + let line = normalize_whitespace( + &file_lines.file.get_line(line_to_remove.line_index).unwrap(), + ); + buffer.puts(*row_num - 1, max_line_num_len + 3, &line, Style::NoStyle); + *row_num += 1; + } + // If the last line is exactly equal to the line we need to add, we can skip both of them. + // This allows us to avoid output like the following: + // 2 - & + // 2 + if true { true } else { false } + // 3 - if true { true } else { false } + // If those lines aren't equal, we print their diff + let last_line_index = file_lines.lines[file_lines.lines.len() - 1].line_index; + let last_line = &file_lines.file.get_line(last_line_index).unwrap(); + if last_line != line_to_add { + buffer.puts( + *row_num - 1, + 0, + &self.maybe_anonymized(line_num + file_lines.lines.len() - 1), + Style::LineNumber, + ); + buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal); + buffer.puts( + *row_num - 1, + max_line_num_len + 3, + &normalize_whitespace(last_line), + Style::NoStyle, + ); + buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber); + buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); + buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle); + } else { + *row_num -= 2; + } } else if is_multiline { + buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber); match &highlight_parts[..] { - [SubstitutionHighlight { start: 0, end }] if *end == line.len() => { + [SubstitutionHighlight { start: 0, end }] if *end == line_to_add.len() => { buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); } [] => { @@ -2210,17 +2229,17 @@ impl EmitterWriter { buffer.puts(*row_num, max_line_num_len + 1, "~ ", Style::Addition); } } + buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle); } else { + buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber); draw_col_separator(buffer, *row_num, max_line_num_len + 1); + buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle); } - // print the suggestion - buffer.append(*row_num, &normalize_whitespace(line), Style::NoStyle); - // Colorize addition/replacements with green. for &SubstitutionHighlight { start, end } in highlight_parts { // Account for tabs when highlighting (#87972). - let tabs: usize = line + let tabs: usize = line_to_add .chars() .take(start) .map(|ch| match ch { diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 6cd56852f9d..b4c12651e7a 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -131,10 +131,14 @@ impl<'a> ExtCtxt<'a> { } } - pub fn trait_bound(&self, path: ast::Path) -> ast::GenericBound { + pub fn trait_bound(&self, path: ast::Path, is_const: bool) -> ast::GenericBound { ast::GenericBound::Trait( self.poly_trait_ref(path.span, path), - ast::TraitBoundModifier::None, + if is_const { + ast::TraitBoundModifier::MaybeConst + } else { + ast::TraitBoundModifier::None + }, ) } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 9158fc08247..04546330915 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -287,7 +287,7 @@ language_item_table! { TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; TryTraitFromYeet, sym::from_yeet, from_yeet_fn, Target::Fn, GenericRequirement::None; - PointerSized, sym::pointer_sized, pointer_sized, Target::Trait, GenericRequirement::Exact(0); + PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0); Poll, sym::Poll, poll, Target::Enum, GenericRequirement::None; PollReady, sym::Ready, poll_ready_variant, Target::Variant, GenericRequirement::None; 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 21e70041810..236e36f28ca 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -246,7 +246,7 @@ fn compare_method_predicate_entailment<'tcx>( let mut wf_tys = FxIndexSet::default(); - let unnormalized_impl_sig = infcx.replace_bound_vars_with_fresh_vars( + let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars( impl_m_span, infer::HigherRankedType, tcx.fn_sig(impl_m.def_id).subst_identity(), @@ -640,7 +640,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let impl_sig = ocx.normalize( &norm_cause, param_env, - infcx.replace_bound_vars_with_fresh_vars( + infcx.instantiate_binder_with_fresh_vars( return_span, infer::HigherRankedType, tcx.fn_sig(impl_m.def_id).subst_identity(), diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 6600e4216bd..8c2423e3ca0 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -176,6 +176,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { bounds.iter().map(|(param, constraint, def_id)| { (param.as_str(), constraint.as_str(), *def_id) }), + None, ); err.emit(); } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index c220956a201..089863a66e7 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -156,7 +156,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // fnmut vs fnonce. If so, we have to defer further processing. if self.closure_kind(substs).is_none() { let closure_sig = substs.as_closure().sig(); - let closure_sig = self.replace_bound_vars_with_fresh_vars( + let closure_sig = self.instantiate_binder_with_fresh_vars( call_expr.span, infer::FnCall, closure_sig, @@ -437,7 +437,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // renormalize the associated types at this point, since they // previously appeared within a `Binder<>` and hence would not // have been normalized before. - let fn_sig = self.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig); + let fn_sig = self.instantiate_binder_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig); let fn_sig = self.normalize(call_expr.span, fn_sig); // Call the generic checker. diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 90c4e5b6540..211fe477a2d 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -544,7 +544,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) .map(|(hir_ty, &supplied_ty)| { // Instantiate (this part of..) S to S', i.e., with fresh variables. - self.replace_bound_vars_with_fresh_vars( + self.instantiate_binder_with_fresh_vars( hir_ty.span, LateBoundRegionConversionTime::FnCall, // (*) binder moved to here @@ -566,7 +566,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { all_obligations.extend(obligations); } - let supplied_output_ty = self.replace_bound_vars_with_fresh_vars( + let supplied_output_ty = self.instantiate_binder_with_fresh_vars( decl.output.span(), LateBoundRegionConversionTime::FnCall, supplied_sig.output(), diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index ade9c037c51..7173239ba61 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -765,7 +765,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.cause.clone(), self.param_env, ty::Binder::dummy( - self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerSized, [a]), + self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerLike, [a]), ), )); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 3561992e86a..bb235a48361 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -568,7 +568,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // placeholder lifetimes with probing, we just replace higher lifetimes // with fresh vars. let span = args.get(i).map(|a| a.span).unwrap_or(expr.span); - let input = self.replace_bound_vars_with_fresh_vars( + let input = self.instantiate_binder_with_fresh_vars( span, infer::LateBoundRegionConversionTime::FnCall, fn_sig.input(i), @@ -586,7 +586,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Also, as we just want to check sizedness, instead of introducing // placeholder lifetimes with probing, we just replace higher lifetimes // with fresh vars. - let output = self.replace_bound_vars_with_fresh_vars( + let output = self.instantiate_binder_with_fresh_vars( expr.span, infer::LateBoundRegionConversionTime::FnCall, fn_sig.output(), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 2eab68050d4..db1acb59927 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -1,10 +1,382 @@ use crate::FnCtxt; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_middle::ty::{self, DefIdTree, Ty}; +use rustc_hir::def_id::DefId; +use rustc_infer::traits::ObligationCauseCode; +use rustc_middle::ty::{self, DefIdTree, Ty, TypeSuperVisitable, TypeVisitable, TypeVisitor}; +use rustc_span::{self, Span}; use rustc_trait_selection::traits; +use std::ops::ControlFlow; + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub fn adjust_fulfillment_error_for_expr_obligation( + &self, + error: &mut traits::FulfillmentError<'tcx>, + ) -> bool { + let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx)) + = *error.obligation.cause.code().peel_derives() else { return false; }; + let hir = self.tcx.hir(); + let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; }; + + let Some(unsubstituted_pred) = + self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx) + else { return false; }; + + let generics = self.tcx.generics_of(def_id); + let predicate_substs = match unsubstituted_pred.kind().skip_binder() { + ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs, + ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs, + _ => ty::List::empty(), + }; + + let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| { + predicate_substs.types().find_map(|ty| { + ty.walk().find_map(|arg| { + if let ty::GenericArgKind::Type(ty) = arg.unpack() + && let ty::Param(param_ty) = ty.kind() + && matches(param_ty) + { + Some(arg) + } else { + None + } + }) + }) + }; + + // Prefer generics that are local to the fn item, since these are likely + // to be the cause of the unsatisfied predicate. + let mut param_to_point_at = find_param_matching(&|param_ty| { + self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id + }); + // Fall back to generic that isn't local to the fn item. This will come + // from a trait or impl, for example. + let mut fallback_param_to_point_at = find_param_matching(&|param_ty| { + self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id + && param_ty.name != rustc_span::symbol::kw::SelfUpper + }); + // Finally, the `Self` parameter is possibly the reason that the predicate + // is unsatisfied. This is less likely to be true for methods, because + // method probe means that we already kinda check that the predicates due + // to the `Self` type are true. + let mut self_param_to_point_at = + find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper); + + // Finally, for ambiguity-related errors, we actually want to look + // for a parameter that is the source of the inference type left + // over in this predicate. + if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code { + fallback_param_to_point_at = None; + self_param_to_point_at = None; + param_to_point_at = + self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate); + } + + if self.closure_span_overlaps_error(error, expr.span) { + return false; + } + + match &expr.kind { + hir::ExprKind::Path(qpath) => { + if let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Call(callee, args), + hir_id: call_hir_id, + span: call_span, + .. + }) = hir.get_parent(expr.hir_id) + && callee.hir_id == expr.hir_id + { + if self.closure_span_overlaps_error(error, *call_span) { + return false; + } + + for param in + [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] + .into_iter() + .flatten() + { + if self.blame_specific_arg_if_possible( + error, + def_id, + param, + *call_hir_id, + callee.span, + None, + args, + ) + { + return true; + } + } + } + // Notably, we only point to params that are local to the + // item we're checking, since those are the ones we are able + // to look in the final `hir::PathSegment` for. Everything else + // would require a deeper search into the `qpath` than I think + // is worthwhile. + if let Some(param_to_point_at) = param_to_point_at + && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath) + { + return true; + } + } + hir::ExprKind::MethodCall(segment, receiver, args, ..) => { + for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] + .into_iter() + .flatten() + { + if self.blame_specific_arg_if_possible( + error, + def_id, + param, + hir_id, + segment.ident.span, + Some(receiver), + args, + ) { + return true; + } + } + if let Some(param_to_point_at) = param_to_point_at + && self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment) + { + return true; + } + } + hir::ExprKind::Struct(qpath, fields, ..) => { + if let Res::Def( + hir::def::DefKind::Struct | hir::def::DefKind::Variant, + variant_def_id, + ) = self.typeck_results.borrow().qpath_res(qpath, hir_id) + { + for param in + [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] + { + if let Some(param) = param { + let refined_expr = self.point_at_field_if_possible( + def_id, + param, + variant_def_id, + fields, + ); + + match refined_expr { + None => {} + Some((refined_expr, _)) => { + error.obligation.cause.span = refined_expr + .span + .find_ancestor_in_same_ctxt(error.obligation.cause.span) + .unwrap_or(refined_expr.span); + return true; + } + } + } + } + } + if let Some(param_to_point_at) = param_to_point_at + && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath) + { + return true; + } + } + _ => {} + } + + false + } + + fn point_at_path_if_possible( + &self, + error: &mut traits::FulfillmentError<'tcx>, + def_id: DefId, + param: ty::GenericArg<'tcx>, + qpath: &hir::QPath<'tcx>, + ) -> bool { + match qpath { + hir::QPath::Resolved(_, path) => { + if let Some(segment) = path.segments.last() + && self.point_at_generic_if_possible(error, def_id, param, segment) + { + return true; + } + } + hir::QPath::TypeRelative(_, segment) => { + if self.point_at_generic_if_possible(error, def_id, param, segment) { + return true; + } + } + _ => {} + } + + false + } + + fn point_at_generic_if_possible( + &self, + error: &mut traits::FulfillmentError<'tcx>, + def_id: DefId, + param_to_point_at: ty::GenericArg<'tcx>, + segment: &hir::PathSegment<'tcx>, + ) -> bool { + let own_substs = self + .tcx + .generics_of(def_id) + .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id)); + let Some((index, _)) = own_substs + .iter() + .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_))) + .enumerate() + .find(|(_, arg)| **arg == param_to_point_at) else { return false }; + let Some(arg) = segment + .args() + .args + .iter() + .filter(|arg| matches!(arg, hir::GenericArg::Type(_))) + .nth(index) else { return false; }; + error.obligation.cause.span = arg + .span() + .find_ancestor_in_same_ctxt(error.obligation.cause.span) + .unwrap_or(arg.span()); + true + } + + fn find_ambiguous_parameter_in<T: TypeVisitable<'tcx>>( + &self, + item_def_id: DefId, + t: T, + ) -> Option<ty::GenericArg<'tcx>> { + struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId); + impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> { + type BreakTy = ty::GenericArg<'tcx>; + fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> { + if let Some(origin) = self.0.type_var_origin(ty) + && let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) = + origin.kind + && let generics = self.0.tcx.generics_of(self.1) + && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id) + && let Some(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1) + .get(index as usize) + { + ControlFlow::Break(*subst) + } else { + ty.super_visit_with(self) + } + } + } + t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value() + } + + fn closure_span_overlaps_error( + &self, + error: &traits::FulfillmentError<'tcx>, + span: Span, + ) -> bool { + if let traits::FulfillmentErrorCode::CodeSelectionError( + traits::SelectionError::OutputTypeParameterMismatch(_, expected, _), + ) = error.code + && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind() + && span.overlaps(self.tcx.def_span(*def_id)) + { + true + } else { + false + } + } + + fn point_at_field_if_possible( + &self, + def_id: DefId, + param_to_point_at: ty::GenericArg<'tcx>, + variant_def_id: DefId, + expr_fields: &[hir::ExprField<'tcx>], + ) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> { + let def = self.tcx.adt_def(def_id); + + let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id); + let fields_referencing_param: Vec<_> = def + .variant_with_id(variant_def_id) + .fields + .iter() + .filter(|field| { + let field_ty = field.ty(self.tcx, identity_substs); + Self::find_param_in_ty(field_ty.into(), param_to_point_at) + }) + .collect(); + + if let [field] = fields_referencing_param.as_slice() { + for expr_field in expr_fields { + // Look for the ExprField that matches the field, using the + // same rules that check_expr_struct uses for macro hygiene. + if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx) + { + return Some((expr_field.expr, self.tcx.type_of(field.did))); + } + } + } + + None + } + + /// - `blame_specific_*` means that the function will recursively traverse the expression, + /// looking for the most-specific-possible span to blame. + /// + /// - `point_at_*` means that the function will only go "one level", pointing at the specific + /// expression mentioned. + /// + /// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside + /// the provided function call expression, and mark it as responsible for the fullfillment + /// error. + fn blame_specific_arg_if_possible( + &self, + error: &mut traits::FulfillmentError<'tcx>, + def_id: DefId, + param_to_point_at: ty::GenericArg<'tcx>, + call_hir_id: hir::HirId, + callee_span: Span, + receiver: Option<&'tcx hir::Expr<'tcx>>, + args: &'tcx [hir::Expr<'tcx>], + ) -> bool { + let ty = self.tcx.type_of(def_id); + if !ty.is_fn() { + return false; + } + let sig = ty.fn_sig(self.tcx).skip_binder(); + let args_referencing_param: Vec<_> = sig + .inputs() + .iter() + .enumerate() + .filter(|(_, ty)| Self::find_param_in_ty((**ty).into(), param_to_point_at)) + .collect(); + // If there's one field that references the given generic, great! + if let [(idx, _)] = args_referencing_param.as_slice() + && let Some(arg) = receiver + .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) { + + error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span); + + if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) { + // This is more specific than pointing at the entire argument. + self.blame_specific_expr_if_possible(error, arg_expr) + } + + error.obligation.cause.map_code(|parent_code| { + ObligationCauseCode::FunctionArgumentObligation { + arg_hir_id: arg.hir_id, + call_hir_id, + parent_code, + } + }); + return true; + } else if args_referencing_param.len() > 0 { + // If more than one argument applies, then point to the callee span at least... + // We have chance to fix this up further in `point_at_generics_if_possible` + error.obligation.cause.span = callee_span; + } + + false + } + /** * Recursively searches for the most-specific blamable expression. * For example, if you have a chain of constraints like: diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 1055ee953ea..2a1265600de 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -26,7 +26,7 @@ use rustc_infer::infer::InferOk; use rustc_infer::infer::TypeTrace; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty, TypeSuperVisitable, TypeVisitor}; +use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty}; use rustc_session::Session; use rustc_span::symbol::{kw, Ident}; use rustc_span::{self, sym, Span}; @@ -36,8 +36,6 @@ use std::iter; use std::mem; use std::slice; -use std::ops::ControlFlow; - impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn check_casts(&mut self) { // don't hold the borrow to deferred_cast_checks while checking to avoid borrow checker errors @@ -1758,372 +1756,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn adjust_fulfillment_error_for_expr_obligation( - &self, - error: &mut traits::FulfillmentError<'tcx>, - ) -> bool { - let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx)) - = *error.obligation.cause.code().peel_derives() else { return false; }; - let hir = self.tcx.hir(); - let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; }; - - let Some(unsubstituted_pred) = - self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx) - else { return false; }; - - let generics = self.tcx.generics_of(def_id); - let predicate_substs = match unsubstituted_pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs, - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs, - _ => ty::List::empty(), - }; - - let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| { - predicate_substs.types().find_map(|ty| { - ty.walk().find_map(|arg| { - if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Param(param_ty) = ty.kind() - && matches(param_ty) - { - Some(arg) - } else { - None - } - }) - }) - }; - - // Prefer generics that are local to the fn item, since these are likely - // to be the cause of the unsatisfied predicate. - let mut param_to_point_at = find_param_matching(&|param_ty| { - self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id - }); - // Fall back to generic that isn't local to the fn item. This will come - // from a trait or impl, for example. - let mut fallback_param_to_point_at = find_param_matching(&|param_ty| { - self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id - && param_ty.name != rustc_span::symbol::kw::SelfUpper - }); - // Finally, the `Self` parameter is possibly the reason that the predicate - // is unsatisfied. This is less likely to be true for methods, because - // method probe means that we already kinda check that the predicates due - // to the `Self` type are true. - let mut self_param_to_point_at = - find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper); - - // Finally, for ambiguity-related errors, we actually want to look - // for a parameter that is the source of the inference type left - // over in this predicate. - if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code { - fallback_param_to_point_at = None; - self_param_to_point_at = None; - param_to_point_at = - self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate); - } - - if self.closure_span_overlaps_error(error, expr.span) { - return false; - } - - match &expr.kind { - hir::ExprKind::Path(qpath) => { - if let hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Call(callee, args), - hir_id: call_hir_id, - span: call_span, - .. - }) = hir.get_parent(expr.hir_id) - && callee.hir_id == expr.hir_id - { - if self.closure_span_overlaps_error(error, *call_span) { - return false; - } - - for param in - [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] - .into_iter() - .flatten() - { - if self.blame_specific_arg_if_possible( - error, - def_id, - param, - *call_hir_id, - callee.span, - None, - args, - ) - { - return true; - } - } - } - // Notably, we only point to params that are local to the - // item we're checking, since those are the ones we are able - // to look in the final `hir::PathSegment` for. Everything else - // would require a deeper search into the `qpath` than I think - // is worthwhile. - if let Some(param_to_point_at) = param_to_point_at - && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath) - { - return true; - } - } - hir::ExprKind::MethodCall(segment, receiver, args, ..) => { - for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] - .into_iter() - .flatten() - { - if self.blame_specific_arg_if_possible( - error, - def_id, - param, - hir_id, - segment.ident.span, - Some(receiver), - args, - ) { - return true; - } - } - if let Some(param_to_point_at) = param_to_point_at - && self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment) - { - return true; - } - } - hir::ExprKind::Struct(qpath, fields, ..) => { - if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) = - self.typeck_results.borrow().qpath_res(qpath, hir_id) - { - for param in - [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] - { - if let Some(param) = param { - let refined_expr = self.point_at_field_if_possible( - def_id, - param, - variant_def_id, - fields, - ); - - match refined_expr { - None => {} - Some((refined_expr, _)) => { - error.obligation.cause.span = refined_expr - .span - .find_ancestor_in_same_ctxt(error.obligation.cause.span) - .unwrap_or(refined_expr.span); - return true; - } - } - } - } - } - if let Some(param_to_point_at) = param_to_point_at - && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath) - { - return true; - } - } - _ => {} - } - - false - } - - fn closure_span_overlaps_error( - &self, - error: &traits::FulfillmentError<'tcx>, - span: Span, - ) -> bool { - if let traits::FulfillmentErrorCode::CodeSelectionError( - traits::SelectionError::OutputTypeParameterMismatch(_, expected, _), - ) = error.code - && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind() - && span.overlaps(self.tcx.def_span(*def_id)) - { - true - } else { - false - } - } - - /// - `blame_specific_*` means that the function will recursively traverse the expression, - /// looking for the most-specific-possible span to blame. - /// - /// - `point_at_*` means that the function will only go "one level", pointing at the specific - /// expression mentioned. - /// - /// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside - /// the provided function call expression, and mark it as responsible for the fullfillment - /// error. - fn blame_specific_arg_if_possible( - &self, - error: &mut traits::FulfillmentError<'tcx>, - def_id: DefId, - param_to_point_at: ty::GenericArg<'tcx>, - call_hir_id: hir::HirId, - callee_span: Span, - receiver: Option<&'tcx hir::Expr<'tcx>>, - args: &'tcx [hir::Expr<'tcx>], - ) -> bool { - let ty = self.tcx.type_of(def_id); - if !ty.is_fn() { - return false; - } - let sig = ty.fn_sig(self.tcx).skip_binder(); - let args_referencing_param: Vec<_> = sig - .inputs() - .iter() - .enumerate() - .filter(|(_, ty)| Self::find_param_in_ty((**ty).into(), param_to_point_at)) - .collect(); - // If there's one field that references the given generic, great! - if let [(idx, _)] = args_referencing_param.as_slice() - && let Some(arg) = receiver - .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) { - - error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span); - - if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) { - // This is more specific than pointing at the entire argument. - self.blame_specific_expr_if_possible(error, arg_expr) - } - - error.obligation.cause.map_code(|parent_code| { - ObligationCauseCode::FunctionArgumentObligation { - arg_hir_id: arg.hir_id, - call_hir_id, - parent_code, - } - }); - return true; - } else if args_referencing_param.len() > 0 { - // If more than one argument applies, then point to the callee span at least... - // We have chance to fix this up further in `point_at_generics_if_possible` - error.obligation.cause.span = callee_span; - } - - false - } - - // FIXME: Make this private and move to mod adjust_fulfillment_errors - pub fn point_at_field_if_possible( - &self, - def_id: DefId, - param_to_point_at: ty::GenericArg<'tcx>, - variant_def_id: DefId, - expr_fields: &[hir::ExprField<'tcx>], - ) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> { - let def = self.tcx.adt_def(def_id); - - let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id); - let fields_referencing_param: Vec<_> = def - .variant_with_id(variant_def_id) - .fields - .iter() - .filter(|field| { - let field_ty = field.ty(self.tcx, identity_substs); - Self::find_param_in_ty(field_ty.into(), param_to_point_at) - }) - .collect(); - - if let [field] = fields_referencing_param.as_slice() { - for expr_field in expr_fields { - // Look for the ExprField that matches the field, using the - // same rules that check_expr_struct uses for macro hygiene. - if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx) - { - return Some((expr_field.expr, self.tcx.type_of(field.did))); - } - } - } - - None - } - - fn point_at_path_if_possible( - &self, - error: &mut traits::FulfillmentError<'tcx>, - def_id: DefId, - param: ty::GenericArg<'tcx>, - qpath: &QPath<'tcx>, - ) -> bool { - match qpath { - hir::QPath::Resolved(_, path) => { - if let Some(segment) = path.segments.last() - && self.point_at_generic_if_possible(error, def_id, param, segment) - { - return true; - } - } - hir::QPath::TypeRelative(_, segment) => { - if self.point_at_generic_if_possible(error, def_id, param, segment) { - return true; - } - } - _ => {} - } - - false - } - - fn point_at_generic_if_possible( - &self, - error: &mut traits::FulfillmentError<'tcx>, - def_id: DefId, - param_to_point_at: ty::GenericArg<'tcx>, - segment: &hir::PathSegment<'tcx>, - ) -> bool { - let own_substs = self - .tcx - .generics_of(def_id) - .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id)); - let Some((index, _)) = own_substs - .iter() - .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_))) - .enumerate() - .find(|(_, arg)| **arg == param_to_point_at) else { return false }; - let Some(arg) = segment - .args() - .args - .iter() - .filter(|arg| matches!(arg, hir::GenericArg::Type(_))) - .nth(index) else { return false; }; - error.obligation.cause.span = arg - .span() - .find_ancestor_in_same_ctxt(error.obligation.cause.span) - .unwrap_or(arg.span()); - true - } - - fn find_ambiguous_parameter_in<T: TypeVisitable<'tcx>>( - &self, - item_def_id: DefId, - t: T, - ) -> Option<ty::GenericArg<'tcx>> { - struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId); - impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> { - type BreakTy = ty::GenericArg<'tcx>; - fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> { - if let Some(origin) = self.0.type_var_origin(ty) - && let TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) = - origin.kind - && let generics = self.0.tcx.generics_of(self.1) - && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id) - && let Some(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1) - .get(index as usize) - { - ControlFlow::Break(*subst) - } else { - ty.super_visit_with(self) - } - } - } - t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value() - } - fn label_fn_like( &self, err: &mut Diagnostic, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 1e14eddd4c8..3814ddaf73f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -289,7 +289,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { item_segment: &hir::PathSegment<'_>, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Ty<'tcx> { - let trait_ref = self.replace_bound_vars_with_fresh_vars( + let trait_ref = self.instantiate_binder_with_fresh_vars( span, infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), poly_trait_ref, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 51e3e3ec73d..eaad57d8c2e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1336,16 +1336,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::Path { segments: [segment], .. }, )) | hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) => { - let self_ty = self.astconv().ast_ty_to_ty(ty); - if let Ok(pick) = self.probe_for_name( - Mode::Path, - Ident::new(capitalized_name, segment.ident.span), - Some(expected_ty), - IsSuggestion(true), - self_ty, - expr.hir_id, - ProbeScope::TraitsInScope, - ) { + if let Some(self_ty) = self.typeck_results.borrow().node_type_opt(ty.hir_id) + && let Ok(pick) = self.probe_for_name( + Mode::Path, + Ident::new(capitalized_name, segment.ident.span), + Some(expected_ty), + IsSuggestion(true), + self_ty, + expr.hir_id, + ProbeScope::TraitsInScope, + ) + { (pick.item, segment) } else { return false; @@ -1457,6 +1458,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { generics, diag, vec![(param.name.as_str(), "Clone", Some(clone_trait_did))].into_iter(), + None, ); } else { self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]); diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 65ca47bfe53..fa0dc4d8415 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -262,7 +262,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let original_poly_trait_ref = principal.with_self_ty(this.tcx, object_ty); let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id); let upcast_trait_ref = - this.replace_bound_vars_with_fresh_vars(upcast_poly_trait_ref); + this.instantiate_binder_with_fresh_vars(upcast_poly_trait_ref); debug!( "original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}", original_poly_trait_ref, upcast_trait_ref, trait_def_id @@ -285,7 +285,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { probe::WhereClausePick(poly_trait_ref) => { // Where clauses can have bound regions in them. We need to instantiate // those to convert from a poly-trait-ref to a trait-ref. - self.replace_bound_vars_with_fresh_vars(poly_trait_ref).substs + self.instantiate_binder_with_fresh_vars(poly_trait_ref).substs } } } @@ -506,7 +506,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let sig = self.tcx.fn_sig(def_id).subst(self.tcx, all_substs); debug!("type scheme substituted, sig={:?}", sig); - let sig = self.replace_bound_vars_with_fresh_vars(sig); + let sig = self.instantiate_binder_with_fresh_vars(sig); debug!("late-bound lifetimes from method instantiated, sig={:?}", sig); (sig, method_predicates) @@ -625,10 +625,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { upcast_trait_refs.into_iter().next().unwrap() } - fn replace_bound_vars_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T + fn instantiate_binder_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T where T: TypeFoldable<'tcx> + Copy, { - self.fcx.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, value) + self.fcx.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, value) } } diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 60d4dc326ee..d5d10cf272a 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -401,7 +401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // with bound regions. let fn_sig = tcx.fn_sig(def_id).subst(self.tcx, substs); let fn_sig = - self.replace_bound_vars_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig); + self.instantiate_binder_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig); let InferOk { value, obligations: o } = self.at(&obligation.cause, self.param_env).normalize(fn_sig); diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 9ab29a6778f..4ce401b52bd 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -924,7 +924,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ty::AssocKind::Fn => self.probe(|_| { let substs = self.fresh_substs_for_item(self.span, method.def_id); let fty = self.tcx.fn_sig(method.def_id).subst(self.tcx, substs); - let fty = self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, fty); + let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty); if let Some(self_ty) = self_ty { if self diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 3e8e7734a5a..7cc9e49b1b6 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -268,14 +268,12 @@ impl<'tcx> InferCtxt<'tcx> { (GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => { // To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`. if v_o != v_r { - output_query_region_constraints.outlives.push(( - ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)), - constraint_category, - )); - output_query_region_constraints.outlives.push(( - ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)), - constraint_category, - )); + output_query_region_constraints + .outlives + .push((ty::OutlivesPredicate(v_o.into(), v_r), constraint_category)); + output_query_region_constraints + .outlives + .push((ty::OutlivesPredicate(v_r.into(), v_o), constraint_category)); } } @@ -318,10 +316,8 @@ impl<'tcx> InferCtxt<'tcx> { query_response.value.region_constraints.outlives.iter().filter_map(|&r_c| { let r_c = substitute_value(self.tcx, &result_subst, r_c); - // Screen out `'a: 'a` cases -- we skip the binder here but - // only compare the inner values to one another, so they are still at - // consistent binding levels. - let ty::OutlivesPredicate(k1, r2) = r_c.0.skip_binder(); + // Screen out `'a: 'a` cases. + let ty::OutlivesPredicate(k1, r2) = r_c.0; if k1 != r2.into() { Some(r_c) } else { None } }), ); @@ -559,11 +555,11 @@ impl<'tcx> InferCtxt<'tcx> { pub fn query_outlives_constraint_to_obligation( &self, - predicate: QueryOutlivesConstraint<'tcx>, + (predicate, _): QueryOutlivesConstraint<'tcx>, cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Obligation<'tcx, ty::Predicate<'tcx>> { - let ty::OutlivesPredicate(k1, r2) = predicate.0.skip_binder(); + let ty::OutlivesPredicate(k1, r2) = predicate; let atom = match k1.unpack() { GenericArgKind::Lifetime(r1) => { @@ -578,7 +574,7 @@ impl<'tcx> InferCtxt<'tcx> { span_bug!(cause.span, "unexpected const outlives {:?}", predicate); } }; - let predicate = predicate.0.rebind(atom); + let predicate = ty::Binder::dummy(atom); Obligation::new(self.tcx, cause, param_env, predicate) } @@ -643,8 +639,7 @@ pub fn make_query_region_constraints<'tcx>( let outlives: Vec<_> = constraints .iter() .map(|(k, origin)| { - // no bound vars in the code above - let constraint = ty::Binder::dummy(match *k { + let constraint = match *k { // Swap regions because we are going from sub (<=) to outlives // (>=). Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate( @@ -658,16 +653,12 @@ pub fn make_query_region_constraints<'tcx>( ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1) } Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1), - }); + }; (constraint, origin.to_constraint_category()) }) - .chain( - outlives_obligations - // no bound vars in the code above - .map(|(ty, r, constraint_category)| { - (ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), r)), constraint_category) - }), - ) + .chain(outlives_obligations.map(|(ty, r, constraint_category)| { + (ty::OutlivesPredicate(ty.into(), r), constraint_category) + })) .collect(); QueryRegionConstraints { outlives, member_constraints: member_constraints.clone() } diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 46e7813d99e..7db4d92a177 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -129,7 +129,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { let a_types = infcx.tcx.anonymize_bound_vars(a_types); let b_types = infcx.tcx.anonymize_bound_vars(b_types); if a_types.bound_vars() == b_types.bound_vars() { - let (a_types, b_types) = infcx.replace_bound_vars_with_placeholders( + let (a_types, b_types) = infcx.instantiate_binder_with_placeholders( a_types.map_bound(|a_types| (a_types, b_types.skip_binder())), ); for (a, b) in std::iter::zip(a_types, b_types) { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b5c2d14e8d1..86f3174b7b2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1922,7 +1922,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (ty::Uint(ty::UintTy::U8), ty::Char) => { if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) && let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) - && code.chars().next().map_or(false, |c| c.is_ascii()) + && !code.starts_with("\\u") // forbid all Unicode escapes + && code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII { err.span_suggestion( span, diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 39b3c98f0a5..984e8cf6a0e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -77,49 +77,86 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p)) if tcx.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder => { - let generics = tcx.generics_of(body_owner_def_id); - let p_span = tcx.def_span(generics.type_param(p, tcx).def_id); + let p_def_id = tcx + .generics_of(body_owner_def_id) + .type_param(p, tcx) + .def_id; + let p_span = tcx.def_span(p_def_id); if !sp.contains(p_span) { diag.span_label(p_span, "this type parameter"); } let hir = tcx.hir(); let mut note = true; - if let Some(generics) = generics - .type_param(p, tcx) - .def_id + let parent = p_def_id .as_local() - .map(|id| hir.local_def_id_to_hir_id(id)) - .and_then(|id| tcx.hir().find_parent(id)) - .as_ref() - .and_then(|node| node.generics()) + .and_then(|id| { + let local_id = hir.local_def_id_to_hir_id(id); + let generics = tcx.hir().find_parent(local_id)?.generics()?; + Some((id, generics)) + }); + if let Some((local_id, generics)) = parent { // Synthesize the associated type restriction `Add<Output = Expected>`. // FIXME: extract this logic for use in other diagnostics. let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(tcx); - let path = - tcx.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs); let item_name = tcx.item_name(proj.def_id); let item_args = self.format_generic_args(assoc_substs); - let path = if path.ends_with('>') { - format!( - "{}, {}{} = {}>", - &path[..path.len() - 1], - item_name, - item_args, - p - ) + // Here, we try to see if there's an existing + // trait implementation that matches the one that + // we're suggesting to restrict. If so, find the + // "end", whether it be at the end of the trait + // or the end of the generic arguments. + let mut matching_span = None; + let mut matched_end_of_args = false; + for bound in generics.bounds_for_param(local_id) { + let potential_spans = bound + .bounds + .iter() + .find_map(|bound| { + let bound_trait_path = bound.trait_ref()?.path; + let def_id = bound_trait_path.res.opt_def_id()?; + let generic_args = bound_trait_path.segments.iter().last().map(|path| path.args()); + (def_id == trait_ref.def_id).then_some((bound_trait_path.span, generic_args)) + }); + + if let Some((end_of_trait, end_of_args)) = potential_spans { + let args_span = end_of_args.and_then(|args| args.span()); + matched_end_of_args = args_span.is_some(); + matching_span = args_span + .or_else(|| Some(end_of_trait)) + .map(|span| span.shrink_to_hi()); + break; + } + } + + if matched_end_of_args { + // Append suggestion to the end of our args + let path = format!(", {}{} = {}",item_name, item_args, p); + note = !suggest_constraining_type_param( + tcx, + generics, + diag, + &format!("{}", proj.self_ty()), + &path, + None, + matching_span, + ); } else { - format!("{}<{}{} = {}>", path, item_name, item_args, p) - }; - note = !suggest_constraining_type_param( - tcx, - generics, - diag, - &format!("{}", proj.self_ty()), - &path, - None, - ); + // Suggest adding a bound to an existing trait + // or if the trait doesn't exist, add the trait + // and the suggested bounds. + let path = format!("<{}{} = {}>", item_name, item_args, p); + note = !suggest_constraining_type_param( + tcx, + generics, + diag, + &format!("{}", proj.self_ty()), + &path, + None, + matching_span, + ); + } } if note { diag.note("you might be missing a type parameter or trait bound"); diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index 31be107b354..412e52d8fd7 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -38,13 +38,13 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { // First, we instantiate each bound region in the supertype with a // fresh placeholder region. Note that this automatically creates // a new universe if needed. - let sup_prime = self.infcx.replace_bound_vars_with_placeholders(sup); + let sup_prime = self.infcx.instantiate_binder_with_placeholders(sup); // Next, we instantiate each bound region in the subtype // with a fresh region variable. These region variables -- // but no other pre-existing region variables -- can name // the placeholders. - let sub_prime = self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, sub); + let sub_prime = self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub); debug!("a_prime={:?}", sub_prime); debug!("b_prime={:?}", sup_prime); @@ -70,7 +70,7 @@ impl<'tcx> InferCtxt<'tcx> { /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html #[instrument(level = "debug", skip(self), ret)] - pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T + pub fn instantiate_binder_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T where T: TypeFoldable<'tcx> + Copy, { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 8e0bcff8d0a..35918b8bae1 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -995,7 +995,7 @@ impl<'tcx> InferCtxt<'tcx> { Ok(self.commit_if_ok(|_snapshot| { let ty::SubtypePredicate { a_is_expected, a, b } = - self.replace_bound_vars_with_placeholders(predicate); + self.instantiate_binder_with_placeholders(predicate); let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; @@ -1008,7 +1008,7 @@ impl<'tcx> InferCtxt<'tcx> { cause: &traits::ObligationCause<'tcx>, predicate: ty::PolyRegionOutlivesPredicate<'tcx>, ) { - let ty::OutlivesPredicate(r_a, r_b) = self.replace_bound_vars_with_placeholders(predicate); + let ty::OutlivesPredicate(r_a, r_b) = self.instantiate_binder_with_placeholders(predicate); let origin = SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span)); self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` @@ -1447,7 +1447,14 @@ impl<'tcx> InferCtxt<'tcx> { value } - pub fn replace_bound_vars_with_fresh_vars<T>( + // Instantiates the bound variables in a given binder with fresh inference + // variables in the current universe. + // + // Use this method if you'd like to find some substitution of the binder's + // variables (e.g. during a method call). If there isn't a [`LateBoundRegionConversionTime`] + // that corresponds to your use case, consider whether or not you should + // use [`InferCtxt::instantiate_binder_with_placeholders`] instead. + pub fn instantiate_binder_with_fresh_vars<T>( &self, span: Span, lbrct: LateBoundRegionConversionTime, diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 51c34f0d55f..532fbd0ffe4 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -161,7 +161,7 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { let a_types = infcx.tcx.anonymize_bound_vars(a_types); let b_types = infcx.tcx.anonymize_bound_vars(b_types); if a_types.bound_vars() == b_types.bound_vars() { - let (a_types, b_types) = infcx.replace_bound_vars_with_placeholders( + let (a_types, b_types) = infcx.instantiate_binder_with_placeholders( a_types.map_bound(|a_types| (a_types, b_types.skip_binder())), ); for (a, b) in std::iter::zip(a_types, b_types) { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 52a4e0e7418..5165ee424e3 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -758,7 +758,6 @@ fn test_unstable_options_tracking_hash() { tracked!(link_only, true); tracked!(llvm_plugins, vec![String::from("plugin_name")]); tracked!(location_detail, LocationDetail { file: true, line: false, column: false }); - tracked!(log_backtrace, Some("filter".to_string())); tracked!(maximal_hir_to_mir_coverage, true); tracked!(merge_functions, Some(MergeFunctions::Disabled)); tracked!(mir_emit_retag, true); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 7e9ba4cd22b..9d8ad9d9ed9 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4073,7 +4073,8 @@ declare_lint! { declare_lint! { /// The `byte_slice_in_packed_struct_with_derive` lint detects cases where a byte slice field - /// (`[u8]`) is used in a `packed` struct that derives one or more built-in traits. + /// (`[u8]`) or string slice field (`str`) is used in a `packed` struct that derives one or + /// more built-in traits. /// /// ### Example /// @@ -4091,11 +4092,11 @@ declare_lint! { /// ### Explanation /// /// This was previously accepted but is being phased out, because fields in packed structs are - /// now required to implement `Copy` for `derive` to work. Byte slices are a temporary - /// exception because certain crates depended on them. + /// now required to implement `Copy` for `derive` to work. Byte slices and string slices are a + /// temporary exception because certain crates depended on them. pub BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, Warn, - "`[u8]` slice used in a packed struct with `derive`", + "`[u8]` or `str` used in a packed struct with `derive`", @future_incompatible = FutureIncompatibleInfo { reference: "issue #107457 <https://github.com/rust-lang/rust/issues/107457>", reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index 727cfc4416e..9146a3739b2 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -4,7 +4,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Triple.h" #include "llvm/Analysis/Lint.h" #include "llvm/Analysis/Passes.h" #include "llvm/IR/IRBuilder.h" @@ -44,6 +43,12 @@ #include "llvm/IR/IRPrintingPasses.h" #include "llvm/Linker/Linker.h" +#if LLVM_VERSION_GE(16, 0) +#include "llvm/TargetParser/Triple.h" +#else +#include "llvm/ADT/Triple.h" +#endif + extern "C" void LLVMRustSetLastError(const char *); enum class LLVMRustResult { Success, Failure }; diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index fc1cabd2de9..019fdc30dce 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs @@ -54,25 +54,12 @@ use tracing_subscriber::fmt::{ use tracing_subscriber::layer::SubscriberExt; pub fn init_rustc_env_logger() -> Result<(), Error> { - init_rustc_env_logger_with_backtrace_option(&None) -} - -pub fn init_rustc_env_logger_with_backtrace_option( - backtrace_target: &Option<String>, -) -> Result<(), Error> { - init_env_logger_with_backtrace_option("RUSTC_LOG", backtrace_target) + init_env_logger("RUSTC_LOG") } /// In contrast to `init_rustc_env_logger` this allows you to choose an env var /// other than `RUSTC_LOG`. pub fn init_env_logger(env: &str) -> Result<(), Error> { - init_env_logger_with_backtrace_option(env, &None) -} - -pub fn init_env_logger_with_backtrace_option( - env: &str, - backtrace_target: &Option<String>, -) -> Result<(), Error> { let filter = match env::var(env) { Ok(env) => EnvFilter::new(env), _ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)), @@ -106,8 +93,8 @@ pub fn init_env_logger_with_backtrace_option( let layer = layer.with_thread_ids(true).with_thread_names(true); let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer); - match backtrace_target { - Some(str) => { + match env::var(format!("{env}_BACKTRACE")) { + Ok(str) => { let fmt_layer = tracing_subscriber::fmt::layer() .with_writer(io::stderr) .without_time() @@ -115,7 +102,7 @@ pub fn init_env_logger_with_backtrace_option( let subscriber = subscriber.with(fmt_layer); tracing::subscriber::set_global_default(subscriber).unwrap(); } - None => { + Err(_) => { tracing::subscriber::set_global_default(subscriber).unwrap(); } }; diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 21652063b47..bf8b8aa2ce4 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -356,7 +356,12 @@ impl<'a> CrateLoader<'a> { for (_, other) in self.cstore.iter_crate_data() { // Same stable crate id but different SVH if other.stable_crate_id() == root.stable_crate_id() && other.hash() != root.hash() { - return Err(CrateError::SymbolConflictsOthers(root.name())); + bug!( + "Previously returned E0523 here. \ + See https://github.com/rust-lang/rust/pull/100599 for additional discussion.\ + root.name() = {}.", + root.name() + ); } } diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 02c03114eb6..c32686779fa 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -512,14 +512,6 @@ pub struct SymbolConflictsCurrent { } #[derive(Diagnostic)] -#[diag(metadata_symbol_conflicts_others, code = "E0523")] -pub struct SymbolConflictsOthers { - #[primary_span] - pub span: Span, - pub crate_name: Symbol, -} - -#[derive(Diagnostic)] #[diag(metadata_stable_crate_id_collision)] pub struct StableCrateIdCollision { #[primary_span] diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 74f91a14ea9..755a2425350 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -945,7 +945,6 @@ pub(crate) enum CrateError { ExternLocationNotFile(Symbol, PathBuf), MultipleCandidates(Symbol, CrateFlavor, Vec<PathBuf>), SymbolConflictsCurrent(Symbol), - SymbolConflictsOthers(Symbol), StableCrateIdCollision(Symbol, Symbol), DlOpen(String), DlSym(String), @@ -989,9 +988,6 @@ impl CrateError { CrateError::SymbolConflictsCurrent(root_name) => { sess.emit_err(errors::SymbolConflictsCurrent { span, crate_name: root_name }); } - CrateError::SymbolConflictsOthers(root_name) => { - sess.emit_err(errors::SymbolConflictsOthers { span, crate_name: root_name }); - } CrateError::StableCrateIdCollision(crate_name0, crate_name1) => { sess.emit_err(errors::StableCrateIdCollision { span, crate_name0, crate_name1 }); } diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 6e130bbf7d8..d6f20a8fc06 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -324,10 +324,8 @@ impl<'tcx, V> Canonical<'tcx, V> { } } -pub type QueryOutlivesConstraint<'tcx> = ( - ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>, - ConstraintCategory<'tcx>, -); +pub type QueryOutlivesConstraint<'tcx> = + (ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>); TrivialTypeTraversalAndLiftImpls! { for <'tcx> { diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index bd9cd53e115..f22c0dbc60d 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -430,8 +430,10 @@ pub enum ResourceExhaustionInfo { /// /// The exact limit is set by the `const_eval_limit` attribute. StepLimitReached, - /// There is not enough memory to perform an allocation. + /// There is not enough memory (on the host) to perform an allocation. MemoryExhausted, + /// The address space (of the target) is full. + AddressSpaceFull, } impl fmt::Display for ResourceExhaustionInfo { @@ -447,6 +449,9 @@ impl fmt::Display for ResourceExhaustionInfo { MemoryExhausted => { write!(f, "tried to allocate more memory than available to compiler") } + AddressSpaceFull => { + write!(f, "there are no more free addresses in the address space") + } } } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 4cebe416354..0a16ede6499 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -54,14 +54,14 @@ rustc_queries! { /// This is because the `hir_crate` query gives you access to all other items. /// To avoid this fate, do not call `tcx.hir().krate()`; instead, /// prefer wrappers like `tcx.visit_all_items_in_krate()`. - query hir_crate(key: ()) -> Crate<'tcx> { + query hir_crate(key: ()) -> &'tcx Crate<'tcx> { arena_cache eval_always desc { "getting the crate HIR" } } /// All items in the crate. - query hir_crate_items(_: ()) -> rustc_middle::hir::ModuleItems { + query hir_crate_items(_: ()) -> &'tcx rustc_middle::hir::ModuleItems { arena_cache eval_always desc { "getting HIR crate items" } @@ -71,7 +71,7 @@ rustc_queries! { /// /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`. /// Avoid calling this query directly. - query hir_module_items(key: LocalDefId) -> rustc_middle::hir::ModuleItems { + query hir_module_items(key: LocalDefId) -> &'tcx rustc_middle::hir::ModuleItems { arena_cache desc { |tcx| "getting HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) } cache_on_disk_if { true } @@ -183,7 +183,7 @@ rustc_queries! { separate_provide_extern } - query unsizing_params_for_adt(key: DefId) -> rustc_index::bit_set::BitSet<u32> + query unsizing_params_for_adt(key: DefId) -> &'tcx rustc_index::bit_set::BitSet<u32> { arena_cache desc { |tcx| @@ -218,7 +218,7 @@ rustc_queries! { /// Maps from the `DefId` of an item (trait/struct/enum/fn) to its /// associated generics. - query generics_of(key: DefId) -> ty::Generics { + query generics_of(key: DefId) -> &'tcx ty::Generics { desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) } arena_cache cache_on_disk_if { key.is_local() } @@ -295,19 +295,19 @@ rustc_queries! { /// These are assembled from the following places: /// - `extern` blocks (depending on their `link` attributes) /// - the `libs` (`-l`) option - query native_libraries(_: CrateNum) -> Vec<NativeLib> { + query native_libraries(_: CrateNum) -> &'tcx Vec<NativeLib> { arena_cache desc { "looking up the native libraries of a linked crate" } separate_provide_extern } - query shallow_lint_levels_on(key: hir::OwnerId) -> rustc_middle::lint::ShallowLintLevelMap { + query shallow_lint_levels_on(key: hir::OwnerId) -> &'tcx rustc_middle::lint::ShallowLintLevelMap { eval_always // fetches `resolutions` arena_cache desc { |tcx| "looking up lint levels for `{}`", tcx.def_path_str(key.to_def_id()) } } - query lint_expectations(_: ()) -> Vec<(LintExpectationId, LintExpectation)> { + query lint_expectations(_: ()) -> &'tcx Vec<(LintExpectationId, LintExpectation)> { arena_cache desc { "computing `#[expect]`ed lints in this crate" } } @@ -347,7 +347,7 @@ rustc_queries! { } /// Set of param indexes for type params that are in the type's representation - query params_in_repr(key: DefId) -> rustc_index::bit_set::BitSet<u32> { + query params_in_repr(key: DefId) -> &'tcx rustc_index::bit_set::BitSet<u32> { desc { "finding type parameters in the representation" } arena_cache no_hash @@ -364,14 +364,14 @@ rustc_queries! { } /// Create a THIR tree for debugging. - query thir_tree(key: ty::WithOptConstParam<LocalDefId>) -> String { + query thir_tree(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx String { no_hash arena_cache desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) } } /// Create a list-like THIR representation for debugging. - query thir_flat(key: ty::WithOptConstParam<LocalDefId>) -> String { + query thir_flat(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx String { no_hash arena_cache desc { |tcx| "constructing flat THIR representation for `{}`", tcx.def_path_str(key.did.to_def_id()) } @@ -380,7 +380,7 @@ rustc_queries! { /// Set of all the `DefId`s in this crate that have MIR associated with /// them. This includes all the body owners, but also things like struct /// constructors. - query mir_keys(_: ()) -> rustc_data_structures::fx::FxIndexSet<LocalDefId> { + query mir_keys(_: ()) -> &'tcx rustc_data_structures::fx::FxIndexSet<LocalDefId> { arena_cache desc { "getting a list of all mir_keys" } } @@ -478,7 +478,7 @@ rustc_queries! { query symbols_for_closure_captures( key: (LocalDefId, LocalDefId) - ) -> Vec<rustc_span::Symbol> { + ) -> &'tcx Vec<rustc_span::Symbol> { arena_cache desc { |tcx| "finding symbols for captures of closure `{}` in `{}`", @@ -487,7 +487,7 @@ rustc_queries! { } } - query mir_generator_witnesses(key: DefId) -> mir::GeneratorLayout<'tcx> { + query mir_generator_witnesses(key: DefId) -> &'tcx mir::GeneratorLayout<'tcx> { arena_cache desc { |tcx| "generator witness types for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } @@ -508,14 +508,14 @@ rustc_queries! { /// Returns coverage summary info for a function, after executing the `InstrumentCoverage` /// MIR pass (assuming the -Cinstrument-coverage option is enabled). - query coverageinfo(key: ty::InstanceDef<'tcx>) -> mir::CoverageInfo { + query coverageinfo(key: ty::InstanceDef<'tcx>) -> &'tcx mir::CoverageInfo { desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key.def_id()) } arena_cache } /// Returns the `CodeRegions` for a function that has instrumented coverage, in case the /// function was optimized out before codegen, and before being added to the Coverage Map. - query covered_code_regions(key: DefId) -> Vec<&'tcx mir::coverage::CodeRegion> { + query covered_code_regions(key: DefId) -> &'tcx Vec<&'tcx mir::coverage::CodeRegion> { desc { |tcx| "retrieving the covered `CodeRegion`s, if instrumented, for `{}`", tcx.def_path_str(key) @@ -557,7 +557,7 @@ rustc_queries! { desc { "erasing regions from `{}`", ty } } - query wasm_import_module_map(_: CrateNum) -> FxHashMap<DefId, String> { + query wasm_import_module_map(_: CrateNum) -> &'tcx FxHashMap<DefId, String> { arena_cache desc { "getting wasm import module map" } } @@ -632,7 +632,7 @@ rustc_queries! { desc { |tcx| "computing the bounds for type parameter `{}`", tcx.hir().ty_param_name(key.1) } } - query trait_def(key: DefId) -> ty::TraitDef { + query trait_def(key: DefId) -> &'tcx ty::TraitDef { desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) } arena_cache cache_on_disk_if { key.is_local() } @@ -703,7 +703,7 @@ rustc_queries! { } /// Gets a map with the variance of every item; use `item_variance` instead. - query crate_variances(_: ()) -> ty::CrateVariancesMap<'tcx> { + query crate_variances(_: ()) -> &'tcx ty::CrateVariancesMap<'tcx> { arena_cache desc { "computing the variances for items in this crate" } } @@ -716,7 +716,7 @@ rustc_queries! { } /// Maps from thee `DefId` of a type to its (inferred) outlives. - query inferred_outlives_crate(_: ()) -> ty::CratePredicatesMap<'tcx> { + query inferred_outlives_crate(_: ()) -> &'tcx ty::CratePredicatesMap<'tcx> { arena_cache desc { "computing the inferred outlives predicates for items in this crate" } } @@ -729,7 +729,7 @@ rustc_queries! { } /// Maps from a trait item to the trait item "descriptor". - query associated_item(key: DefId) -> ty::AssocItem { + query associated_item(key: DefId) -> &'tcx ty::AssocItem { desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) } arena_cache cache_on_disk_if { key.is_local() } @@ -737,7 +737,7 @@ rustc_queries! { } /// Collects the associated items defined on a trait or impl. - query associated_items(key: DefId) -> ty::AssocItems<'tcx> { + query associated_items(key: DefId) -> &'tcx ty::AssocItems<'tcx> { arena_cache desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) } } @@ -763,7 +763,7 @@ rustc_queries! { /// /// The map returned for `tcx.impl_item_implementor_ids(impl_id)` would be ///`{ trait_f: impl_f, trait_g: impl_g }` - query impl_item_implementor_ids(impl_id: DefId) -> FxHashMap<DefId, DefId> { + query impl_item_implementor_ids(impl_id: DefId) -> &'tcx FxHashMap<DefId, DefId> { arena_cache desc { |tcx| "comparing impl items against trait for `{}`", tcx.def_path_str(impl_id) } } @@ -884,7 +884,7 @@ rustc_queries! { /// /// The second return value maps from ADTs to ignored derived traits (e.g. Debug and Clone) and /// their respective impl (i.e., part of the derive macro) - query live_symbols_and_ignored_derived_traits(_: ()) -> ( + query live_symbols_and_ignored_derived_traits(_: ()) -> &'tcx ( FxHashSet<LocalDefId>, FxHashMap<LocalDefId, Vec<(DefId, DefId)>> ) { @@ -964,7 +964,7 @@ rustc_queries! { /// Gets a complete map from all types to their inherent impls. /// Not meant to be used directly outside of coherence. - query crate_inherent_impls(k: ()) -> CrateInherentImpls { + query crate_inherent_impls(k: ()) -> &'tcx CrateInherentImpls { arena_cache desc { "finding all inherent impls defined in crate" } } @@ -1099,7 +1099,7 @@ rustc_queries! { desc { "checking for private elements in public interfaces" } } - query reachable_set(_: ()) -> FxHashSet<LocalDefId> { + query reachable_set(_: ()) -> &'tcx FxHashSet<LocalDefId> { arena_cache desc { "reachability" } } @@ -1111,7 +1111,7 @@ rustc_queries! { } /// Generates a MIR body for the shim. - query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> { + query mir_shims(key: ty::InstanceDef<'tcx>) -> &'tcx mir::Body<'tcx> { arena_cache desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) } } @@ -1191,7 +1191,7 @@ rustc_queries! { separate_provide_extern } - query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs { + query codegen_fn_attrs(def_id: DefId) -> &'tcx CodegenFnAttrs { desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) } arena_cache cache_on_disk_if { def_id.is_local() } @@ -1209,7 +1209,7 @@ rustc_queries! { } /// Gets the rendered value of the specified constant or associated constant. /// Used by rustdoc. - query rendered_const(def_id: DefId) -> String { + query rendered_const(def_id: DefId) -> &'tcx String { arena_cache desc { |tcx| "rendering constant initializer of `{}`", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } @@ -1268,12 +1268,12 @@ rustc_queries! { } /// Given a trait `trait_id`, return all known `impl` blocks. - query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls { + query trait_impls_of(trait_id: DefId) -> &'tcx ty::trait_def::TraitImpls { arena_cache desc { |tcx| "finding trait impls of `{}`", tcx.def_path_str(trait_id) } } - query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph { + query specialization_graph_of(trait_id: DefId) -> &'tcx specialization_graph::Graph { arena_cache desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) } cache_on_disk_if { true } @@ -1403,7 +1403,7 @@ rustc_queries! { separate_provide_extern } - query dependency_formats(_: ()) -> Lrc<crate::middle::dependency_format::Dependencies> { + query dependency_formats(_: ()) -> &'tcx Lrc<crate::middle::dependency_format::Dependencies> { arena_cache desc { "getting the linkage format of all dependencies" } } @@ -1503,7 +1503,7 @@ rustc_queries! { // Does not include external symbols that don't have a corresponding DefId, // like the compiler-generated `main` function and so on. query reachable_non_generics(_: CrateNum) - -> DefIdMap<SymbolExportInfo> { + -> &'tcx DefIdMap<SymbolExportInfo> { arena_cache desc { "looking up the exported symbols of a crate" } separate_provide_extern @@ -1526,7 +1526,7 @@ rustc_queries! { /// added or removed in any upstream crate. Instead use the narrower /// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even /// better, `Instance::upstream_monomorphization()`. - query upstream_monomorphizations(_: ()) -> DefIdMap<FxHashMap<SubstsRef<'tcx>, CrateNum>> { + query upstream_monomorphizations(_: ()) -> &'tcx DefIdMap<FxHashMap<SubstsRef<'tcx>, CrateNum>> { arena_cache desc { "collecting available upstream monomorphizations" } } @@ -1541,7 +1541,6 @@ rustc_queries! { query upstream_monomorphizations_for(def_id: DefId) -> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>> { - arena_cache desc { |tcx| "collecting available upstream monomorphizations for `{}`", tcx.def_path_str(def_id), @@ -1569,7 +1568,7 @@ rustc_queries! { } /// Returns a list of all `extern` blocks of a crate. - query foreign_modules(_: CrateNum) -> FxHashMap<DefId, ForeignModule> { + query foreign_modules(_: CrateNum) -> &'tcx FxHashMap<DefId, ForeignModule> { arena_cache desc { "looking up the foreign modules of a linked crate" } separate_provide_extern @@ -1603,7 +1602,7 @@ rustc_queries! { /// Gets the extra data to put in each output filename for a crate. /// For example, compiling the `foo` crate with `extra-filename=-a` creates a `libfoo-b.rlib` file. - query extra_filename(_: CrateNum) -> String { + query extra_filename(_: CrateNum) -> &'tcx String { arena_cache eval_always desc { "looking up the extra filename for a crate" } @@ -1611,7 +1610,7 @@ rustc_queries! { } /// Gets the paths where the crate came from in the file system. - query crate_extern_paths(_: CrateNum) -> Vec<PathBuf> { + query crate_extern_paths(_: CrateNum) -> &'tcx Vec<PathBuf> { arena_cache eval_always desc { "looking up the paths for extern crates" } @@ -1642,7 +1641,7 @@ rustc_queries! { /// Does lifetime resolution on items. Importantly, we can't resolve /// lifetimes directly on things like trait methods, because of trait params. /// See `rustc_resolve::late::lifetimes for details. - query resolve_lifetimes(_: hir::OwnerId) -> ResolveLifetimes { + query resolve_lifetimes(_: hir::OwnerId) -> &'tcx ResolveLifetimes { arena_cache desc { "resolving lifetimes" } } @@ -1713,7 +1712,7 @@ rustc_queries! { desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) } } - query lib_features(_: ()) -> LibFeatures { + query lib_features(_: ()) -> &'tcx LibFeatures { arena_cache desc { "calculating the lib features map" } } @@ -1721,7 +1720,7 @@ rustc_queries! { desc { "calculating the lib features defined in a crate" } separate_provide_extern } - query stability_implications(_: CrateNum) -> FxHashMap<Symbol, Symbol> { + query stability_implications(_: CrateNum) -> &'tcx FxHashMap<Symbol, Symbol> { arena_cache desc { "calculating the implications between `#[unstable]` features defined in a crate" } separate_provide_extern @@ -1732,14 +1731,14 @@ rustc_queries! { separate_provide_extern } /// Returns the lang items defined in another crate by loading it from metadata. - query get_lang_items(_: ()) -> LanguageItems { + query get_lang_items(_: ()) -> &'tcx LanguageItems { arena_cache eval_always desc { "calculating the lang items map" } } /// Returns all diagnostic items defined in all crates. - query all_diagnostic_items(_: ()) -> rustc_hir::diagnostic_items::DiagnosticItems { + query all_diagnostic_items(_: ()) -> &'tcx rustc_hir::diagnostic_items::DiagnosticItems { arena_cache eval_always desc { "calculating the diagnostic items map" } @@ -1752,7 +1751,7 @@ rustc_queries! { } /// Returns the diagnostic items defined in a crate. - query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems { + query diagnostic_items(_: CrateNum) -> &'tcx rustc_hir::diagnostic_items::DiagnosticItems { arena_cache desc { "calculating the diagnostic items map in a crate" } separate_provide_extern @@ -1762,11 +1761,11 @@ rustc_queries! { desc { "calculating the missing lang items in a crate" } separate_provide_extern } - query visible_parent_map(_: ()) -> DefIdMap<DefId> { + query visible_parent_map(_: ()) -> &'tcx DefIdMap<DefId> { arena_cache desc { "calculating the visible parent map" } } - query trimmed_def_paths(_: ()) -> FxHashMap<DefId, Symbol> { + query trimmed_def_paths(_: ()) -> &'tcx FxHashMap<DefId, Symbol> { arena_cache desc { "calculating trimmed def paths" } } @@ -1775,14 +1774,14 @@ rustc_queries! { desc { "seeing if we're missing an `extern crate` item for this crate" } separate_provide_extern } - query used_crate_source(_: CrateNum) -> Lrc<CrateSource> { + query used_crate_source(_: CrateNum) -> &'tcx Lrc<CrateSource> { arena_cache eval_always desc { "looking at the source for a crate" } separate_provide_extern } /// Returns the debugger visualizers defined for this crate. - query debugger_visualizers(_: CrateNum) -> Vec<rustc_span::DebuggerVisualizerFile> { + query debugger_visualizers(_: CrateNum) -> &'tcx Vec<rustc_span::DebuggerVisualizerFile> { arena_cache desc { "looking up the debugger visualizers for this crate" } separate_provide_extern @@ -1820,7 +1819,7 @@ rustc_queries! { desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id.to_def_id()) } } - query stability_index(_: ()) -> stability::Index { + query stability_index(_: ()) -> &'tcx stability::Index { arena_cache eval_always desc { "calculating the stability index for the local crate" } @@ -1884,7 +1883,7 @@ rustc_queries! { /// /// This query returns an `&Arc` because codegen backends need the value even after the `TyCtxt` /// has been destroyed. - query output_filenames(_: ()) -> Arc<OutputFilenames> { + query output_filenames(_: ()) -> &'tcx Arc<OutputFilenames> { feedable desc { "getting output filenames" } arena_cache @@ -2057,7 +2056,7 @@ rustc_queries! { remap_env_constness } - query supported_target_features(_: CrateNum) -> FxHashMap<String, Option<Symbol>> { + query supported_target_features(_: CrateNum) -> &'tcx FxHashMap<String, Option<Symbol>> { arena_cache eval_always desc { "looking up supported target features" } @@ -2116,23 +2115,24 @@ rustc_queries! { /// span) for an *existing* error. Therefore, it is best-effort, and may never handle /// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine, /// because the `ty::Ty`-based wfcheck is always run. - query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, traits::WellFormedLoc)) -> Option<traits::ObligationCause<'tcx>> { + query diagnostic_hir_wf_check( + key: (ty::Predicate<'tcx>, traits::WellFormedLoc) + ) -> &'tcx Option<traits::ObligationCause<'tcx>> { arena_cache eval_always no_hash desc { "performing HIR wf-checking for predicate `{:?}` at item `{:?}`", key.0, key.1 } } - /// The list of backend features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, /// `--target` and similar). - query global_backend_features(_: ()) -> Vec<String> { + query global_backend_features(_: ()) -> &'tcx Vec<String> { arena_cache eval_always desc { "computing the backend features for CLI flags" } } - query generator_diagnostic_data(key: DefId) -> Option<GeneratorDiagnosticData<'tcx>> { + query generator_diagnostic_data(key: DefId) -> &'tcx Option<GeneratorDiagnosticData<'tcx>> { arena_cache desc { |tcx| "looking up generator diagnostic data of `{}`", tcx.def_path_str(key) } separate_provide_extern diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index cd9b9270140..0a30ae9d0aa 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -193,6 +193,9 @@ fn suggest_removing_unsized_bound( } /// Suggest restricting a type param with a new bound. +/// +/// If `span_to_replace` is provided, then that span will be replaced with the +/// `constraint`. If one wasn't provided, then the full bound will be suggested. pub fn suggest_constraining_type_param( tcx: TyCtxt<'_>, generics: &hir::Generics<'_>, @@ -200,12 +203,14 @@ pub fn suggest_constraining_type_param( param_name: &str, constraint: &str, def_id: Option<DefId>, + span_to_replace: Option<Span>, ) -> bool { suggest_constraining_type_params( tcx, generics, err, [(param_name, constraint, def_id)].into_iter(), + span_to_replace, ) } @@ -215,6 +220,7 @@ pub fn suggest_constraining_type_params<'a>( generics: &hir::Generics<'_>, err: &mut Diagnostic, param_names_and_constraints: impl Iterator<Item = (&'a str, &'a str, Option<DefId>)>, + span_to_replace: Option<Span>, ) -> bool { let mut grouped = FxHashMap::default(); param_names_and_constraints.for_each(|(param_name, constraint, def_id)| { @@ -253,7 +259,9 @@ pub fn suggest_constraining_type_params<'a>( let mut suggest_restrict = |span, bound_list_non_empty| { suggestions.push(( span, - if bound_list_non_empty { + if span_to_replace.is_some() { + constraint.clone() + } else if bound_list_non_empty { format!(" + {}", constraint) } else { format!(" {}", constraint) @@ -262,6 +270,11 @@ pub fn suggest_constraining_type_params<'a>( )) }; + if let Some(span) = span_to_replace { + suggest_restrict(span, true); + continue; + } + // When the type parameter has been provided bounds // // Message: diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 7151b79c5ab..933aaadd62e 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -112,15 +112,15 @@ macro_rules! query_helper_param_ty { ($K:ty) => { $K }; } -macro_rules! query_storage { - ([][$K:ty, $V:ty]) => { - <<$K as Key>::CacheSelector as CacheSelector<'tcx, $V>>::Cache +macro_rules! query_if_arena { + ([] $arena:ty, $no_arena:ty) => { + $no_arena }; - ([(arena_cache) $($rest:tt)*][$K:ty, $V:ty]) => { - <<$K as Key>::CacheSelector as CacheSelector<'tcx, $V>>::ArenaCache + ([(arena_cache) $($rest:tt)*] $arena:ty, $no_arena:ty) => { + $arena }; - ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { - query_storage!([$($modifiers)*][$($args)*]) + ([$other:tt $($modifiers:tt)*]$($args:tt)*) => { + query_if_arena!([$($modifiers)*]$($args)*) }; } @@ -184,23 +184,30 @@ macro_rules! define_callbacks { $(pub type $name<'tcx> = $($K)*;)* } - #[allow(nonstandard_style, unused_lifetimes)] + #[allow(nonstandard_style, unused_lifetimes, unused_parens)] pub mod query_values { use super::*; - $(pub type $name<'tcx> = $V;)* + $(pub type $name<'tcx> = query_if_arena!([$($modifiers)*] <$V as Deref>::Target, $V);)* } - #[allow(nonstandard_style, unused_lifetimes)] + #[allow(nonstandard_style, unused_lifetimes, unused_parens)] pub mod query_storage { use super::*; - $(pub type $name<'tcx> = query_storage!([$($modifiers)*][$($K)*, $V]);)* + $( + pub type $name<'tcx> = query_if_arena!([$($modifiers)*] + <<$($K)* as Key>::CacheSelector + as CacheSelector<'tcx, <$V as Deref>::Target>>::ArenaCache, + <<$($K)* as Key>::CacheSelector as CacheSelector<'tcx, $V>>::Cache + ); + )* } + #[allow(nonstandard_style, unused_lifetimes)] pub mod query_stored { use super::*; - $(pub type $name<'tcx> = <query_storage::$name<'tcx> as QueryStorage>::Stored;)* + $(pub type $name<'tcx> = $V;)* } #[derive(Default)] @@ -226,7 +233,7 @@ macro_rules! define_callbacks { $($(#[$attr])* #[inline(always)] #[must_use] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'tcx> + pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V { self.at(DUMMY_SP).$name(key) })* @@ -235,7 +242,7 @@ macro_rules! define_callbacks { impl<'tcx> TyCtxtAt<'tcx> { $($(#[$attr])* #[inline(always)] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'tcx> + pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V { let key = key.into_query_param(); opt_remap_env_constness!([$($modifiers)*][key]); @@ -306,7 +313,7 @@ macro_rules! define_callbacks { span: Span, key: query_keys::$name<'tcx>, mode: QueryMode, - ) -> Option<query_stored::$name<'tcx>>;)* + ) -> Option<$V>;)* } }; } @@ -328,7 +335,7 @@ macro_rules! define_feedable { $(impl<'tcx, K: IntoQueryParam<$($K)*> + Copy> TyCtxtFeed<'tcx, K> { $(#[$attr])* #[inline(always)] - pub fn $name(self, value: $V) -> query_stored::$name<'tcx> { + pub fn $name(self, value: query_values::$name<'tcx>) -> $V { let key = self.key().into_query_param(); opt_remap_env_constness!([$($modifiers)*][key]); diff --git a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs index 3224e13f7af..0d466bbe56e 100644 --- a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs +++ b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs @@ -1,5 +1,5 @@ use crate::elaborate_drops::DropFlagState; -use rustc_middle::mir::{self, Body, Location}; +use rustc_middle::mir::{self, Body, Location, Terminator, TerminatorKind}; use rustc_middle::ty::{self, TyCtxt}; use rustc_target::abi::VariantIdx; @@ -194,6 +194,17 @@ pub fn drop_flag_effects_for_location<'tcx, F>( on_all_children_bits(tcx, body, move_data, path, |mpi| callback(mpi, DropFlagState::Absent)) } + // Drop does not count as a move but we should still consider the variable uninitialized. + if let Some(Terminator { kind: TerminatorKind::Drop { place, .. }, .. }) = + body.stmt_at(loc).right() + { + if let LookupResult::Exact(mpi) = move_data.rev_lookup.find(place.as_ref()) { + on_all_children_bits(tcx, body, move_data, mpi, |mpi| { + callback(mpi, DropFlagState::Absent) + }) + } + } + debug!("drop_flag_effects: assignment for location({:?})", loc); for_location_inits(tcx, body, move_data, loc, |mpi| callback(mpi, DropFlagState::Present)); diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 0195693a7cb..115c8afcce0 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -376,7 +376,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { | TerminatorKind::Resume | TerminatorKind::Abort | TerminatorKind::GeneratorDrop - | TerminatorKind::Unreachable => {} + | TerminatorKind::Unreachable + | TerminatorKind::Drop { .. } => {} TerminatorKind::Assert { ref cond, .. } => { self.gather_operand(cond); @@ -391,10 +392,6 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { self.create_move_path(place); self.gather_init(place.as_ref(), InitKind::Deep); } - - TerminatorKind::Drop { place, target: _, unwind: _ } => { - self.gather_move(place); - } TerminatorKind::DropAndReplace { place, ref value, .. } => { self.create_move_path(place); self.gather_operand(value); diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 8bf6493be4b..a6ef2a742c8 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -223,13 +223,13 @@ pub trait ValueAnalysis<'tcx> { self.super_terminator(terminator, state) } - fn super_terminator(&self, terminator: &Terminator<'tcx>, _state: &mut State<Self::Value>) { + fn super_terminator(&self, terminator: &Terminator<'tcx>, state: &mut State<Self::Value>) { match &terminator.kind { TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => { // Effect is applied by `handle_call_return`. } - TerminatorKind::Drop { .. } => { - // We don't track dropped places. + TerminatorKind::Drop { place, .. } => { + state.flood_with(place.as_ref(), self.map(), Self::Value::bottom()); } TerminatorKind::DropAndReplace { .. } | TerminatorKind::Yield { .. } => { // They would have an effect, but are not allowed in this phase. diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index 4c7d45be075..6e279232bcb 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -153,8 +153,9 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) { if let Operand::Move(place) = *operand - && let Some(local) = place.as_local() - && !self.fully_moved.contains(local) + // A move out of a projection of a copy is equivalent to a copy of the original projection. + && !place.has_deref() + && !self.fully_moved.contains(place.local) { *operand = Operand::Copy(place); } diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 65f4956d23a..c2ff8645635 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -18,6 +18,35 @@ use rustc_span::Span; use rustc_target::abi::VariantIdx; use std::fmt; +/// During MIR building, Drop and DropAndReplace terminators are inserted in every place where a drop may occur. +/// However, in this phase, the presence of these terminators does not guarantee that a destructor will run, +/// as the target of the drop may be uninitialized. +/// In general, the compiler cannot determine at compile time whether a destructor will run or not. +/// +/// At a high level, this pass refines Drop and DropAndReplace to only run the destructor if the +/// target is initialized. The way this is achievied is by inserting drop flags for every variable +/// that may be dropped, and then using those flags to determine whether a destructor should run. +/// This pass also removes DropAndReplace, replacing it with a Drop paired with an assign statement. +/// Once this is complete, Drop terminators in the MIR correspond to a call to the "drop glue" or +/// "drop shim" for the type of the dropped place. +/// +/// This pass relies on dropped places having an associated move path, which is then used to determine +/// the initialization status of the place and its descendants. +/// It's worth noting that a MIR containing a Drop without an associated move path is probably ill formed, +/// as it would allow running a destructor on a place behind a reference: +/// +/// ```text +// fn drop_term<T>(t: &mut T) { +// mir!( +// { +// Drop(*t, exit) +// } +// exit = { +// Return() +// } +// ) +// } +/// ``` pub struct ElaborateDrops; impl<'tcx> MirPass<'tcx> for ElaborateDrops { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index a19ea04fa5e..5b92563fc35 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -694,8 +694,9 @@ impl<'a> Parser<'a> { // `where`, so stop if it's it. // We also continue if we find types (not traits), again for error recovery. while self.can_begin_bound() - || self.token.can_begin_type() - || (self.token.is_reserved_ident() && !self.token.is_keyword(kw::Where)) + || (self.may_recover() + && (self.token.can_begin_type() + || (self.token.is_reserved_ident() && !self.token.is_keyword(kw::Where)))) { if self.token.is_keyword(kw::Dyn) { // Account for `&dyn Trait + dyn Other`. diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 47b2fd8f8f4..9443ded704d 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -47,7 +47,7 @@ impl DepNodeIndex { } impl From<DepNodeIndex> for QueryInvocationId { - #[inline] + #[inline(always)] fn from(dep_node_index: DepNodeIndex) -> Self { QueryInvocationId(dep_node_index.as_u32()) } diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index 21c89cbc4f1..9f875b43731 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -23,10 +23,6 @@ pub trait CacheSelector<'tcx, V> { pub trait QueryStorage { type Value: Debug; type Stored: Copy; - - /// Store a value without putting it in the cache. - /// This is meant to be used with cycle errors. - fn store_nocache(&self, value: Self::Value) -> Self::Stored; } pub trait QueryCache: QueryStorage + Sized { @@ -68,12 +64,6 @@ impl<K, V> Default for DefaultCache<K, V> { impl<K: Eq + Hash, V: Copy + Debug> QueryStorage for DefaultCache<K, V> { type Value = V; type Stored = V; - - #[inline] - fn store_nocache(&self, value: Self::Value) -> Self::Stored { - // We have no dedicated storage - value - } } impl<K, V> QueryCache for DefaultCache<K, V> @@ -144,13 +134,6 @@ impl<'tcx, K, V> Default for ArenaCache<'tcx, K, V> { impl<'tcx, K: Eq + Hash, V: Debug + 'tcx> QueryStorage for ArenaCache<'tcx, K, V> { type Value = V; type Stored = &'tcx V; - - #[inline] - fn store_nocache(&self, value: Self::Value) -> Self::Stored { - let value = self.arena.alloc((value, DepNodeIndex::INVALID)); - let value = unsafe { &*(&value.0 as *const _) }; - &value - } } impl<'tcx, K, V: 'tcx> QueryCache for ArenaCache<'tcx, K, V> @@ -231,12 +214,6 @@ impl<K: Idx, V> Default for VecCache<K, V> { impl<K: Eq + Idx, V: Copy + Debug> QueryStorage for VecCache<K, V> { type Value = V; type Stored = V; - - #[inline] - fn store_nocache(&self, value: Self::Value) -> Self::Stored { - // We have no dedicated storage - value - } } impl<K, V> QueryCache for VecCache<K, V> @@ -309,13 +286,6 @@ impl<'tcx, K: Idx, V> Default for VecArenaCache<'tcx, K, V> { impl<'tcx, K: Eq + Idx, V: Debug + 'tcx> QueryStorage for VecArenaCache<'tcx, K, V> { type Value = V; type Stored = &'tcx V; - - #[inline] - fn store_nocache(&self, value: Self::Value) -> Self::Stored { - let value = self.arena.alloc((value, DepNodeIndex::INVALID)); - let value = unsafe { &*(&value.0 as *const _) }; - &value - } } impl<'tcx, K, V: 'tcx> QueryCache for VecArenaCache<'tcx, K, V> diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index ffc413d15f5..ed66d1929c5 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -121,20 +121,17 @@ where #[cold] #[inline(never)] -fn mk_cycle<Qcx, V, R, D: DepKind>( +fn mk_cycle<Qcx, R, D: DepKind>( qcx: Qcx, cycle_error: CycleError<D>, handler: HandleCycleError, - cache: &dyn crate::query::QueryStorage<Value = V, Stored = R>, ) -> R where Qcx: QueryContext + crate::query::HasDepContext<DepKind = D>, - V: std::fmt::Debug + Value<Qcx::DepContext, Qcx::DepKind>, - R: Copy, + R: std::fmt::Debug + Value<Qcx::DepContext, Qcx::DepKind>, { let error = report_cycle(qcx.dep_context().sess(), &cycle_error); - let value = handle_cycle_error(*qcx.dep_context(), &cycle_error, error, handler); - cache.store_nocache(value) + handle_cycle_error(*qcx.dep_context(), &cycle_error, error, handler) } fn handle_cycle_error<Tcx, V>( @@ -346,9 +343,7 @@ where { match cache.lookup(&key) { Some((value, index)) => { - if std::intrinsics::unlikely(tcx.profiler().enabled()) { - tcx.profiler().query_cache_hit(index.into()); - } + tcx.profiler().query_cache_hit(index.into()); tcx.dep_graph().read_index(index); Some(value) } @@ -399,7 +394,7 @@ where (result, Some(dep_node_index)) } TryGetJob::Cycle(error) => { - let result = mk_cycle(qcx, error, Q::HANDLE_CYCLE_ERROR, cache); + let result = mk_cycle(qcx, error, Q::HANDLE_CYCLE_ERROR); (result, None) } #[cfg(parallel_compiler)] @@ -408,9 +403,7 @@ where panic!("value must be in cache after waiting") }; - if std::intrinsics::unlikely(qcx.dep_context().profiler().enabled()) { - qcx.dep_context().profiler().query_cache_hit(index.into()); - } + qcx.dep_context().profiler().query_cache_hit(index.into()); query_blocked_prof_timer.finish_with_query_invocation_id(index.into()); (v, Some(index)) @@ -776,9 +769,7 @@ where // Ensure that only one of them runs the query. let cache = Q::query_cache(qcx); if let Some((_, index)) = cache.lookup(&key) { - if std::intrinsics::unlikely(qcx.dep_context().profiler().enabled()) { - qcx.dep_context().profiler().query_cache_hit(index.into()); - } + qcx.dep_context().profiler().query_cache_hit(index.into()); return; } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 0db4d85ff4b..61cb81aec3d 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1413,8 +1413,6 @@ options! { "what location details should be tracked when using caller_location, either \ `none`, or a comma separated list of location details, for which \ valid options are `file`, `line`, and `column` (default: `file,line,column`)"), - log_backtrace: Option<String> = (None, parse_opt_string, [TRACKED], - "add a backtrace along with logging"), ls: bool = (false, parse_bool, [UNTRACKED], "list the symbols defined by a library crate (default: no)"), macro_backtrace: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 1933360f722..ef417d3e0a7 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1085,7 +1085,7 @@ symbols! { plugins, pointee_trait, pointer, - pointer_sized, + pointer_like, poll, position, post_dash_lto: "post-lto", diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index ccdf6246083..8525b96c0c2 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -128,9 +128,9 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq { goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - // A type is `PointerSized` if we can compute its layout, and that layout + // A type is `PointerLike` if we can compute its layout, and that layout // matches the layout of `usize`. - fn consider_builtin_pointer_sized_candidate( + fn consider_builtin_pointer_like_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; @@ -312,8 +312,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { || lang_items.clone_trait() == Some(trait_def_id) { G::consider_builtin_copy_clone_candidate(self, goal) - } else if lang_items.pointer_sized() == Some(trait_def_id) { - G::consider_builtin_pointer_sized_candidate(self, goal) + } else if lang_items.pointer_like() == Some(trait_def_id) { + G::consider_builtin_pointer_like_candidate(self, goal) } else if let Some(kind) = self.tcx().fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_fn_trait_candidates(self, goal, kind) } else if lang_items.tuple_trait() == Some(trait_def_id) { diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index a2c15123b4f..c1936b7dbe4 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -74,7 +74,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { ) } ty::PredicateKind::Subtype(pred) => { - let (a, b) = infcx.replace_bound_vars_with_placeholders( + let (a, b) = infcx.instantiate_binder_with_placeholders( goal.predicate.kind().rebind((pred.a, pred.b)), ); let expected_found = ExpectedFound::new(true, a, b); @@ -84,7 +84,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { ) } ty::PredicateKind::Coerce(pred) => { - let (a, b) = infcx.replace_bound_vars_with_placeholders( + let (a, b) = infcx.instantiate_binder_with_placeholders( goal.predicate.kind().rebind((pred.a, pred.b)), ); let expected_found = ExpectedFound::new(false, a, b); @@ -94,7 +94,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { ) } ty::PredicateKind::ConstEquate(a, b) => { - let (a, b) = infcx.replace_bound_vars_with_placeholders( + let (a, b) = infcx.instantiate_binder_with_placeholders( goal.predicate.kind().rebind((a, b)), ); let expected_found = ExpectedFound::new(true, a, b); diff --git a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs index 42f597c781d..36f987c9f9c 100644 --- a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs +++ b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs @@ -26,7 +26,7 @@ pub(super) trait InferCtxtExt<'tcx> { rhs: T, ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution>; - fn instantiate_bound_vars_with_infer<T: TypeFoldable<'tcx> + Copy>( + fn instantiate_binder_with_infer<T: TypeFoldable<'tcx> + Copy>( &self, value: ty::Binder<'tcx, T>, ) -> T; @@ -65,11 +65,11 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { }) } - fn instantiate_bound_vars_with_infer<T: TypeFoldable<'tcx> + Copy>( + fn instantiate_binder_with_infer<T: TypeFoldable<'tcx> + Copy>( &self, value: ty::Binder<'tcx, T>, ) -> T { - self.replace_bound_vars_with_fresh_vars( + self.instantiate_binder_with_fresh_vars( DUMMY_SP, LateBoundRegionConversionTime::HigherRankedType, value, diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index e4725c0a1b7..9f092b6018f 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -304,7 +304,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } } } else { - let kind = self.infcx.replace_bound_vars_with_placeholders(kind); + let kind = self.infcx.instantiate_binder_with_placeholders(kind); let goal = goal.with(self.tcx(), ty::Binder::dummy(kind)); let (_, certainty) = self.evaluate_goal(goal)?; self.make_canonical_response(certainty) diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 9f62f686af6..e3ec71d1b4f 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -323,7 +323,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { { ecx.infcx.probe(|_| { let assumption_projection_pred = - ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred); + ecx.infcx.instantiate_binder_with_infer(poly_projection_pred); let nested_goals = ecx.infcx.eq( goal.param_env, goal.predicate.projection_ty, @@ -370,11 +370,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal); } - fn consider_builtin_pointer_sized_candidate( + fn consider_builtin_pointer_like_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - bug!("`PointerSized` does not have an associated type: {:?}", goal); + bug!("`PointerLike` does not have an associated type: {:?}", goal); } fn consider_builtin_fn_trait_candidates( diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index 7514c7ee551..a2ca4bc189c 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -7,7 +7,7 @@ use cache::ProvisionalCache; use overflow::OverflowData; use rustc_index::vec::IndexVec; use rustc_middle::ty::TyCtxt; -use std::collections::hash_map::Entry; +use std::{collections::hash_map::Entry, mem}; rustc_index::newtype_index! { pub struct StackDepth {} @@ -134,12 +134,15 @@ impl<'tcx> SearchGraph<'tcx> { let provisional_entry_index = *cache.lookup_table.get(&goal).unwrap(); let provisional_entry = &mut cache.entries[provisional_entry_index]; let depth = provisional_entry.depth; + // We eagerly update the response in the cache here. If we have to reevaluate + // this goal we use the new response when hitting a cycle, and we definitely + // want to access the final response whenever we look at the cache. + let prev_response = mem::replace(&mut provisional_entry.response, response); + // Was the current goal the root of a cycle and was the provisional response // different from the final one. - if has_been_used && provisional_entry.response != response { - // If so, update the provisional reponse for this goal... - provisional_entry.response = response; - // ...remove all entries whose result depends on this goal + if has_been_used && prev_response != response { + // If so, remove all entries whose result depends on this goal // from the provisional cache... // // That's not completely correct, as a nested goal can also diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 0003dfeaee7..06a72e95d49 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -72,7 +72,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // FIXME: Constness and polarity ecx.infcx.probe(|_| { let assumption_trait_pred = - ecx.infcx.instantiate_bound_vars_with_infer(poly_trait_pred); + ecx.infcx.instantiate_binder_with_infer(poly_trait_pred); let nested_goals = ecx.infcx.eq( goal.param_env, goal.predicate.trait_ref, @@ -131,7 +131,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ) } - fn consider_builtin_pointer_sized_candidate( + fn consider_builtin_pointer_like_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs index 5007a019e18..1ee35a86e62 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -54,7 +54,7 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( } ty::GeneratorWitness(types) => { - Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) + Ok(infcx.instantiate_binder_with_placeholders(types).to_vec()) } ty::GeneratorWitnessMIR(..) => todo!(), @@ -174,7 +174,7 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( } ty::GeneratorWitness(types) => { - Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) + Ok(infcx.instantiate_binder_with_placeholders(types).to_vec()) } ty::GeneratorWitnessMIR(..) => todo!(), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs index 6bf453c3ff0..84045c4d0ed 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs @@ -22,7 +22,7 @@ pub fn recompute_applicable_impls<'tcx>( let impl_may_apply = |impl_def_id| { let ocx = ObligationCtxt::new_in_snapshot(infcx); let placeholder_obligation = - infcx.replace_bound_vars_with_placeholders(obligation.predicate); + infcx.instantiate_binder_with_placeholders(obligation.predicate); let obligation_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref); @@ -47,11 +47,11 @@ pub fn recompute_applicable_impls<'tcx>( let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| { let ocx = ObligationCtxt::new_in_snapshot(infcx); let placeholder_obligation = - infcx.replace_bound_vars_with_placeholders(obligation.predicate); + infcx.instantiate_binder_with_placeholders(obligation.predicate); let obligation_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref); - let param_env_predicate = infcx.replace_bound_vars_with_fresh_vars( + let param_env_predicate = infcx.instantiate_binder_with_fresh_vars( DUMMY_SP, LateBoundRegionConversionTime::HigherRankedType, poly_trait_predicate, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index f6d0b9713f0..cf1e05ada47 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1716,7 +1716,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let (values, err) = if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) = bound_predicate.skip_binder() { - let data = self.replace_bound_vars_with_fresh_vars( + let data = self.instantiate_binder_with_fresh_vars( obligation.cause.span, infer::LateBoundRegionConversionTime::HigherRankedType, bound_predicate.rebind(data), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 87dbf7c3fd6..59aef52910e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -679,6 +679,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ¶m_name, &constraint, Some(trait_pred.def_id()), + None, ) { return; } @@ -897,7 +898,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return false; } - let self_ty = self.replace_bound_vars_with_fresh_vars( + let self_ty = self.instantiate_binder_with_fresh_vars( DUMMY_SP, LateBoundRegionConversionTime::FnCall, trait_pred.self_ty(), @@ -1087,6 +1088,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { param.name.as_str(), "Clone", Some(clone_trait), + None, ); } err.span_suggestion_verbose( @@ -1189,7 +1191,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } }) else { return None; }; - let output = self.replace_bound_vars_with_fresh_vars( + let output = self.instantiate_binder_with_fresh_vars( DUMMY_SP, LateBoundRegionConversionTime::FnCall, output, @@ -1198,7 +1200,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .skip_binder() .iter() .map(|ty| { - self.replace_bound_vars_with_fresh_vars( + self.instantiate_binder_with_fresh_vars( DUMMY_SP, LateBoundRegionConversionTime::FnCall, inputs.rebind(*ty), @@ -3804,13 +3806,13 @@ fn hint_missing_borrow<'tcx>( err: &mut Diagnostic, ) { let found_args = match found.kind() { - ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(), + ty::FnPtr(f) => infcx.instantiate_binder_with_placeholders(*f).inputs().iter(), kind => { span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind) } }; let expected_args = match expected.kind() { - ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(), + ty::FnPtr(f) => infcx.instantiate_binder_with_placeholders(*f).inputs().iter(), kind => { span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind) } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 18d30771035..3adc1e62e0d 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -321,7 +321,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) => { let pred = - ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder)); + ty::Binder::dummy(infcx.instantiate_binder_with_placeholders(binder)); ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)])) } ty::PredicateKind::Ambiguous => ProcessResult::Unchanged, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 53cae3e720c..aa81bc640aa 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -215,7 +215,7 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( let r = infcx.commit_if_ok(|_snapshot| { let old_universe = infcx.universe(); let placeholder_predicate = - infcx.replace_bound_vars_with_placeholders(obligation.predicate); + infcx.instantiate_binder_with_placeholders(obligation.predicate); let new_universe = infcx.universe(); let placeholder_obligation = obligation.with(infcx.tcx, placeholder_predicate); @@ -2046,7 +2046,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( let cause = &obligation.cause; let param_env = obligation.param_env; - let cache_entry = infcx.replace_bound_vars_with_fresh_vars( + let cache_entry = infcx.instantiate_binder_with_fresh_vars( cause.span, LateBoundRegionConversionTime::HigherRankedType, poly_cache_entry, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 7b7abcf552a..e9f7c3bc4cc 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -94,7 +94,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidates_for_transmutability(obligation, &mut candidates); } else if lang_items.tuple_trait() == Some(def_id) { self.assemble_candidate_for_tuple(obligation, &mut candidates); - } else if lang_items.pointer_sized() == Some(def_id) { + } else if lang_items.pointer_like() == Some(def_id) { self.assemble_candidate_for_ptr_sized(obligation, &mut candidates); } else { if lang_items.clone_trait() == Some(def_id) { @@ -488,7 +488,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); let placeholder_trait_predicate = - self.infcx.replace_bound_vars_with_placeholders(poly_trait_predicate); + self.infcx.instantiate_binder_with_placeholders(poly_trait_predicate); // Count only those upcast versions that match the trait-ref // we are looking for. Specifically, do not only check for the diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 94d9eb8f587..fcc4820c2a6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -151,7 +151,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let trait_predicate = self.infcx.shallow_resolve(obligation.predicate); let placeholder_trait_predicate = - self.infcx.replace_bound_vars_with_placeholders(trait_predicate).trait_ref; + self.infcx.instantiate_binder_with_placeholders(trait_predicate).trait_ref; let placeholder_self_ty = placeholder_trait_predicate.self_ty(); let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate); let (def_id, substs) = match *placeholder_self_ty.kind() { @@ -336,7 +336,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let cause = obligation.derived_cause(BuiltinDerivedObligation); let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref); + let trait_ref = self.infcx.instantiate_binder_with_placeholders(poly_trait_ref); let trait_obligations: Vec<PredicateObligation<'_>> = self.impl_or_trait_obligations( &cause, obligation.recursion_depth + 1, @@ -427,7 +427,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); debug!(?obligation, ?index, "confirm_object_candidate"); - let trait_predicate = self.infcx.replace_bound_vars_with_placeholders(obligation.predicate); + let trait_predicate = self.infcx.instantiate_binder_with_placeholders(obligation.predicate); let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty()); let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref); let ty::Dynamic(data, ..) = *self_ty.kind() else { @@ -437,7 +437,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let object_trait_ref = data.principal().unwrap_or_else(|| { span_bug!(obligation.cause.span, "object candidate with no principal") }); - let object_trait_ref = self.infcx.replace_bound_vars_with_fresh_vars( + let object_trait_ref = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, HigherRankedType, object_trait_ref, @@ -629,7 +629,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // Confirm the `type Output: Sized;` bound that is present on `FnOnce` - let output_ty = self.infcx.replace_bound_vars_with_placeholders(sig.output()); + let output_ty = self.infcx.instantiate_binder_with_placeholders(sig.output()); let output_ty = normalize_with_depth_to( self, obligation.param_env, @@ -652,7 +652,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, "confirm_trait_alias_candidate"); let alias_def_id = obligation.predicate.def_id(); - let predicate = self.infcx.replace_bound_vars_with_placeholders(obligation.predicate); + let predicate = self.infcx.instantiate_binder_with_placeholders(obligation.predicate); let trait_ref = predicate.trait_ref; let trait_def_id = trait_ref.def_id; let substs = trait_ref.substs; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 0c6b2406bbd..984d6fde268 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1618,7 +1618,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> smallvec::SmallVec<[(usize, ty::BoundConstness); 2]> { let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); let placeholder_trait_predicate = - self.infcx.replace_bound_vars_with_placeholders(poly_trait_predicate); + self.infcx.instantiate_binder_with_placeholders(poly_trait_predicate); debug!(?placeholder_trait_predicate); let tcx = self.infcx.tcx; @@ -1738,7 +1738,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { potentially_unnormalized_candidates: bool, ) -> ProjectionMatchesProjection { let mut nested_obligations = Vec::new(); - let infer_predicate = self.infcx.replace_bound_vars_with_fresh_vars( + let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, LateBoundRegionConversionTime::HigherRankedType, env_predicate, @@ -2339,7 +2339,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .flat_map(|ty| { let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/ - let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty); + let placeholder_ty = self.infcx.instantiate_binder_with_placeholders(ty); let Normalized { value: normalized_ty, mut obligations } = ensure_sufficient_stack(|| { project::normalize_with_depth( @@ -2418,7 +2418,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> { let placeholder_obligation = - self.infcx.replace_bound_vars_with_placeholders(obligation.predicate); + self.infcx.instantiate_binder_with_placeholders(obligation.predicate); let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref; let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index d5de457a82c..4aa958878d4 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -220,7 +220,8 @@ bitflags! { // which is different from how types/const are freshened. | TypeFlags::HAS_TY_FRESH.bits | TypeFlags::HAS_CT_FRESH.bits - | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits; + | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits + | TypeFlags::HAS_RE_ERASED.bits; /// Does this have `Projection`? const HAS_TY_PROJECTION = 1 << 10; diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index e7bb3055373..3ede95e8431 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -310,47 +310,51 @@ impl<I: Interner> Clone for TyKind<I> { impl<I: Interner> PartialEq for TyKind<I> { #[inline] fn eq(&self, other: &TyKind<I>) -> bool { - tykind_discriminant(self) == tykind_discriminant(other) - && match (self, other) { - (Int(a_i), Int(b_i)) => a_i == b_i, - (Uint(a_u), Uint(b_u)) => a_u == b_u, - (Float(a_f), Float(b_f)) => a_f == b_f, - (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s, - (Foreign(a_d), Foreign(b_d)) => a_d == b_d, - (Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c, - (Slice(a_t), Slice(b_t)) => a_t == b_t, - (RawPtr(a_t), RawPtr(b_t)) => a_t == b_t, - (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m, - (FnDef(a_d, a_s), FnDef(b_d, b_s)) => a_d == b_d && a_s == b_s, - (FnPtr(a_s), FnPtr(b_s)) => a_s == b_s, - (Dynamic(a_p, a_r, a_repr), Dynamic(b_p, b_r, b_repr)) => { - a_p == b_p && a_r == b_r && a_repr == b_repr - } - (Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s, - (Generator(a_d, a_s, a_m), Generator(b_d, b_s, b_m)) => { - a_d == b_d && a_s == b_s && a_m == b_m - } - (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g == b_g, - ( - &GeneratorWitnessMIR(ref a_d, ref a_s), - &GeneratorWitnessMIR(ref b_d, ref b_s), - ) => a_d == b_d && a_s == b_s, - (Tuple(a_t), Tuple(b_t)) => a_t == b_t, - (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p, - (Param(a_p), Param(b_p)) => a_p == b_p, - (Bound(a_d, a_b), Bound(b_d, b_b)) => a_d == b_d && a_b == b_b, - (Placeholder(a_p), Placeholder(b_p)) => a_p == b_p, - (Infer(a_t), Infer(b_t)) => a_t == b_t, - (Error(a_e), Error(b_e)) => a_e == b_e, - (Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => true, - _ => { - debug_assert!( - false, - "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}" - ); - true - } + // You might expect this `match` to be preceded with this: + // + // tykind_discriminant(self) == tykind_discriminant(other) && + // + // but the data patterns in practice are such that a comparison + // succeeds 99%+ of the time, and it's faster to omit it. + match (self, other) { + (Int(a_i), Int(b_i)) => a_i == b_i, + (Uint(a_u), Uint(b_u)) => a_u == b_u, + (Float(a_f), Float(b_f)) => a_f == b_f, + (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s, + (Foreign(a_d), Foreign(b_d)) => a_d == b_d, + (Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c, + (Slice(a_t), Slice(b_t)) => a_t == b_t, + (RawPtr(a_t), RawPtr(b_t)) => a_t == b_t, + (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m, + (FnDef(a_d, a_s), FnDef(b_d, b_s)) => a_d == b_d && a_s == b_s, + (FnPtr(a_s), FnPtr(b_s)) => a_s == b_s, + (Dynamic(a_p, a_r, a_repr), Dynamic(b_p, b_r, b_repr)) => { + a_p == b_p && a_r == b_r && a_repr == b_repr } + (Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s, + (Generator(a_d, a_s, a_m), Generator(b_d, b_s, b_m)) => { + a_d == b_d && a_s == b_s && a_m == b_m + } + (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g == b_g, + (&GeneratorWitnessMIR(ref a_d, ref a_s), &GeneratorWitnessMIR(ref b_d, ref b_s)) => { + a_d == b_d && a_s == b_s + } + (Tuple(a_t), Tuple(b_t)) => a_t == b_t, + (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p, + (Param(a_p), Param(b_p)) => a_p == b_p, + (Bound(a_d, a_b), Bound(b_d, b_b)) => a_d == b_d && a_b == b_b, + (Placeholder(a_p), Placeholder(b_p)) => a_p == b_p, + (Infer(a_t), Infer(b_t)) => a_t == b_t, + (Error(a_e), Error(b_e)) => a_e == b_e, + (Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => true, + _ => { + debug_assert!( + tykind_discriminant(self) != tykind_discriminant(other), + "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}" + ); + false + } + } } } @@ -408,7 +412,7 @@ impl<I: Interner> Ord for TyKind<I> { (Error(a_e), Error(b_e)) => a_e.cmp(b_e), (Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => Ordering::Equal, _ => { - debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}"); + debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}"); Ordering::Equal } } |
