diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 81efdaa44b3..3a0af04f9eb 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -225,7 +225,7 @@ impl AssocOp { AssignOp(_) | // `{ 42 } +=` As | // `{ 42 } as usize` // Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect - // NotEqual | // `{ 42 } != { 42 } struct literals parser recovery. + // NotEqual | // `{ 42 } != { 42 }` struct literals parser recovery. Colon, // `{ 42 }: usize` ) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5352a56b165..b20157f2c7c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1607,7 +1607,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item)) } - /// Given a `parent_def_id`, a list of `lifetimes_in_bounds and a `remapping` hash to be + /// Given a `parent_def_id`, a list of `lifetimes_in_bounds` and a `remapping` hash to be /// filled, this function creates new definitions for `Param` and `Fresh` lifetimes, inserts the /// new definition, adds it to the remapping with the definition of the given lifetime and /// returns a list of lifetimes to be lowered afterwards. diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 1c561375626..2cc009410f4 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -192,7 +192,7 @@ impl<'a> AstValidator<'a> { // We allow these: // - `Option` // - `option::Option` - // - `option::Option::Foo + // - `option::Option::Foo` // // But not these: // - `::Foo` diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 4baf1b6aa87..ffe82b46cfd 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -415,7 +415,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } /// ``` /// - /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`. + /// Here we would be invoked with `fr = 'a` and `outlived_fr = 'b`. pub(crate) fn report_region_error( &mut self, fr: RegionVid, @@ -949,7 +949,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .push_span_label(*span, "this has an implicit `'static` lifetime requirement"); multi_span.push_span_label( ident.span, - "calling this method introduces the `impl`'s 'static` requirement", + "calling this method introduces the `impl`'s `'static` requirement", ); err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span }); err.span_suggestion_verbose( diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 941da2dd3b5..21b5bd7cb94 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -889,7 +889,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// from a universe it can't name; at present, the only way for /// this to be true is if `scc` outlives `'static`. This is /// actually stricter than necessary: ideally, we'd support bounds - /// like `for<'a: 'b`>` that might then allow us to approximate + /// like `for<'a: 'b>` that might then allow us to approximate /// `'a` with `'b` and not `'static`. But it will have to do for /// now. fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) { diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index c361357ca21..8132800f107 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -235,7 +235,7 @@ pub(crate) struct RegionValues { free_regions: SparseBitMatrix, /// Placeholders represent bound regions -- so something like `'a` - /// in for<'a> fn(&'a u32)`. + /// in `for<'a> fn(&'a u32)`. placeholders: SparseBitMatrix, } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 1b3ce2e83a9..253c2ca7c76 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1814,8 +1814,6 @@ extern "C" { /// Creates a legacy pass manager -- only used for final codegen. pub fn LLVMCreatePassManager<'a>() -> &'a mut PassManager<'a>; - pub fn LLVMInitializePasses(); - pub fn LLVMTimeTraceProfilerInitialize(); pub fn LLVMTimeTraceProfilerFinishThread(); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 20b1dd94153..ba58a2e68e9 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -120,8 +120,6 @@ unsafe fn configure_llvm(sess: &Session) { llvm::LLVMTimeTraceProfilerInitialize(); } - llvm::LLVMInitializePasses(); - rustc_llvm::initialize_available_targets(); llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr()); diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index c65d677e8ea..9ad945359b6 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -457,7 +457,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert_eq!(input_len, dest_len, "Return vector length must match input length"); assert!( index < dest_len, - "Index `{}` must be in bounds of vector with length {}`", + "Index `{}` must be in bounds of vector with length {}", index, dest_len ); @@ -477,7 +477,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (input, input_len) = self.operand_to_simd(&args[0])?; assert!( index < input_len, - "index `{}` must be in bounds of vector with length `{}`", + "index `{}` must be in bounds of vector with length {}", index, input_len ); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index e4366f655e4..aa24d9053b9 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -332,7 +332,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { fn check_static(&mut self, def_id: DefId, span: Span) { if self.tcx.is_thread_local_static(def_id) { - self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef"); + self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef`"); } self.check_op_spanned(ops::StaticAccess, span) } diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs index b0d66c32a07..724be5888dd 100644 --- a/compiler/rustc_data_structures/src/stable_hasher/tests.rs +++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs @@ -150,7 +150,7 @@ fn test_isize_compression() { let hash_b = hash(&(b as isize, a as isize)); assert_ne!( hash_a, hash_b, - "The hash stayed the same when permuting values `{a}` and `{b}!", + "The hash stayed the same when permuting values `{a}` and `{b}`!", ); } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index b79835be73a..47a8b4bc488 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -282,7 +282,7 @@ pub(super) fn transcribe<'a>( } // There should be no meta-var declarations in the invocation of a macro. - mbe::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"), + mbe::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl`"), } } } diff --git a/compiler/rustc_hir_analysis/locales/en-US.ftl b/compiler/rustc_hir_analysis/locales/en-US.ftl index 40b5bc2a32e..1d313945b52 100644 --- a/compiler/rustc_hir_analysis/locales/en-US.ftl +++ b/compiler/rustc_hir_analysis/locales/en-US.ftl @@ -147,3 +147,11 @@ hir_analysis_main_function_generic_parameters = `main` function is not allowed t hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions} .label = C-variadic function must have a compatible calling convention + +hir_analysis_cannot_capture_late_bound_ty_in_anon_const = + cannot capture late-bound type parameter in a constant + .label = parameter defined here + +hir_analysis_cannot_capture_late_bound_const_in_anon_const = + cannot capture late-bound const parameter in a constant + .label = parameter defined here 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 b0dc6b1dcac..691d3f8d942 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1873,7 +1873,7 @@ pub(super) fn check_type_bounds<'tcx>( // type Bar =... // } // - // - `impl_trait_ref` would be `<(A, B) as Foo> + // - `impl_trait_ref` would be `<(A, B) as Foo>` // - `impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0) // - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from // the *trait* with the generic associated type parameters (as bound vars). diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 875c5f1fd00..ffb68abf978 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -437,7 +437,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn } // Here we are considering a case of converting - // `S` to S`. As an example, let's imagine a struct `Foo`, + // `S` to `S`. As an example, let's imagine a struct `Foo`, // which acts like a pointer to `U`, but carries along some extra data of type `T`: // // struct Foo { diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index b14e65183aa..65a9052a60a 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -24,6 +24,8 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use std::fmt; +use crate::errors; + trait RegionExt { fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg); @@ -161,6 +163,15 @@ enum Scope<'a> { s: ScopeRef<'a>, }, + /// Disallows capturing non-lifetime binders from parent scopes. + /// + /// This is necessary for something like `for [(); { /* references T */ }]:`, + /// since we don't do something more correct like replacing any captured + /// late-bound vars with early-bound params in the const's own generics. + AnonConstBoundary { + s: ScopeRef<'a>, + }, + Root { opt_parent_item: Option, }, @@ -211,6 +222,7 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { .field("s", &"..") .finish(), Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(), + Scope::AnonConstBoundary { s: _ } => f.debug_struct("AnonConstBoundary").finish(), Scope::Root { opt_parent_item } => { f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish() } @@ -312,7 +324,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { break (vec![], BinderScopeType::Normal); } - Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => { + Scope::Elision { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::AnonConstBoundary { s } => { scope = s; } @@ -1029,6 +1043,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) { self.visit_poly_trait_ref_inner(trait_ref, NonLifetimeBinderAllowed::Allow); } + + fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { + self.with(Scope::AnonConstBoundary { s: self.scope }, |this| { + intravisit::walk_anon_const(this, c); + }); + } } fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifetimeDefault { @@ -1275,7 +1295,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s, .. } => { + | Scope::TraitRefBoundary { s, .. } + | Scope::AnonConstBoundary { s } => { scope = s; } } @@ -1340,7 +1361,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { | Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s, .. } => { + | Scope::TraitRefBoundary { s, .. } + | Scope::AnonConstBoundary { s } => { scope = s; } } @@ -1359,6 +1381,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // search. let mut late_depth = 0; let mut scope = self.scope; + let mut crossed_anon_const = false; let result = loop { match *scope { Scope::Body { s, .. } => { @@ -1392,10 +1415,36 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { | Scope::TraitRefBoundary { s, .. } => { scope = s; } + + Scope::AnonConstBoundary { s } => { + crossed_anon_const = true; + scope = s; + } } }; if let Some(def) = result { + if let ResolvedArg::LateBound(..) = def && crossed_anon_const { + let use_span = self.tcx.hir().span(hir_id); + let def_span = self.tcx.def_span(param_def_id); + match self.tcx.def_kind(param_def_id) { + DefKind::ConstParam => { + self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Const { + use_span, + def_span, + }); + } + DefKind::TyParam => { + self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Type { + use_span, + def_span, + }); + } + _ => unreachable!(), + } + return; + } + self.map.defs.insert(hir_id, def); return; } @@ -1474,7 +1523,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { | Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s, .. } => { + | Scope::TraitRefBoundary { s, .. } + | Scope::AnonConstBoundary { s } => { scope = s; } } @@ -1710,7 +1760,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l, - Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => { + Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s, .. } + | Scope::AnonConstBoundary { s } => { scope = s; } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 203e0f85cad..3e069275775 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -381,3 +381,21 @@ pub(crate) struct VariadicFunctionCompatibleConvention<'a> { pub span: Span, pub conventions: &'a str, } + +#[derive(Diagnostic)] +pub(crate) enum CannotCaptureLateBoundInAnonConst { + #[diag(hir_analysis_cannot_capture_late_bound_ty_in_anon_const)] + Type { + #[primary_span] + use_span: Span, + #[label] + def_span: Span, + }, + #[diag(hir_analysis_cannot_capture_late_bound_const_in_anon_const)] + Const { + #[primary_span] + use_span: Span, + #[label] + def_span: Span, + }, +} diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 34d62987c3b..7ba57b3b7a2 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -315,7 +315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { probe::ProbeScope::TraitsInScope, None, ) { - Ok(pick) => pick.self_ty, + Ok(pick) => eraser.fold_ty(pick.self_ty), Err(_) => rcvr_ty, }; // Remove one layer of references to account for `&mut self` and diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index bcfc61bffb2..4d3969d28aa 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -636,7 +636,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // `&&Some(x,)` `place_foo` // `&Some(x,)` `deref { place_foo}` // `Some(x,)` `deref { deref { place_foo }}` - // (x,)` `field0 { deref { deref { place_foo }}}` <- resulting place + // `(x,)` `field0 { deref { deref { place_foo }}}` <- resulting place // // The above example has no adjustments. If the code were instead the (after adjustments, // equivalent) version diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index e8bc50440e2..4a432328c4d 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -2223,7 +2223,7 @@ fn determine_place_ancestry_relation<'tcx>( /// || drop(&*m.a.field_of_a) /// // Here we really do want to capture `*m.a` because that outlives `'static` /// -/// // If we capture `m`, then the closure no longer outlives `'static' +/// // If we capture `m`, then the closure no longer outlives `'static` /// // it is constrained to `'a` /// } /// ``` diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs index b4b0ea00c50..c550e553bb0 100644 --- a/compiler/rustc_incremental/src/assert_module_sources.rs +++ b/compiler/rustc_incremental/src/assert_module_sources.rs @@ -18,7 +18,7 @@ //! the HIR doesn't change as a result of the annotations, which might //! perturb the reuse results. //! -//! `#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kind="post-lto")] +//! `#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kind="post-lto")]` //! allows for doing a more fine-grained check to see if pre- or post-lto data //! was re-used. diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 15179392c88..cbf169afb18 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -1870,7 +1870,7 @@ impl SparseBitMatrix { } } - /// Subtracts `set from `row`. `set` can be either `BitSet` or + /// Subtracts `set` from `row`. `set` can be either `BitSet` or /// `HybridBitSet`. Has no effect if `row` does not exist. /// /// Returns true if the row was changed. diff --git a/compiler/rustc_infer/locales/en-US.ftl b/compiler/rustc_infer/locales/en-US.ftl index c5b2b6c2d73..e3db44477de 100644 --- a/compiler/rustc_infer/locales/en-US.ftl +++ b/compiler/rustc_infer/locales/en-US.ftl @@ -79,7 +79,7 @@ infer_subtype = ...so that the {$requirement -> [if_else_different] `if` and `else` have incompatible types [no_else] `if` missing an `else` returns `()` [fn_main_correct_type] `main` function has the correct type - [fn_start_correct_type] #[start]` function has the correct type + [fn_start_correct_type] `#[start]` function has the correct type [intristic_correct_type] intrinsic has the correct type [method_correct_type] method receiver has the correct type *[other] types are compatible @@ -92,7 +92,7 @@ infer_subtype_2 = ...so that {$requirement -> [if_else_different] `if` and `else` have incompatible types [no_else] `if` missing an `else` returns `()` [fn_main_correct_type] `main` function has the correct type - [fn_start_correct_type] #[start]` function has the correct type + [fn_start_correct_type] `#[start]` function has the correct type [intristic_correct_type] intrinsic has the correct type [method_correct_type] method receiver has the correct type *[other] types are compatible @@ -277,7 +277,7 @@ infer_tid_consider_borrowing = consider borrowing this type parameter in the tra infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement -infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s 'static` requirement +infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement infer_dtcs_has_req_note = the used `impl` has a `'static` requirement infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement @@ -313,7 +313,7 @@ infer_but_needs_to_satisfy = {$has_param_name -> [false] ...and is required to live as long as `'static` here } .used_here = ...is used here... - .introduced_by_bound = 'static` lifetime requirement introduced by this bound + .introduced_by_bound = `'static` lifetime requirement introduced by this bound infer_more_targeted = {$has_param_name -> [true] `{$param_name}` diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index c952ddc827a..7d9bae735e5 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -369,6 +369,34 @@ impl<'tcx> ToTrace<'tcx> for Const<'tcx> { } } +impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> { + fn to_trace( + _: TyCtxt<'tcx>, + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self, + ) -> TypeTrace<'tcx> { + use GenericArgKind::*; + TypeTrace { + cause: cause.clone(), + values: match (a.unpack(), b.unpack()) { + (Lifetime(a), Lifetime(b)) => Regions(ExpectedFound::new(a_is_expected, a, b)), + (Type(a), Type(b)) => Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + (Const(a), Const(b)) => { + Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) + } + + (Lifetime(_), Type(_) | Const(_)) + | (Type(_), Lifetime(_) | Const(_)) + | (Const(_), Lifetime(_) | Type(_)) => { + bug!("relating different kinds: {a:?} {b:?}") + } + }, + } + } +} + impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> { fn to_trace( _: TyCtxt<'tcx>, diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 7ffd39de781..678c4a0beb6 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -50,7 +50,7 @@ impl<'tcx> InferCtxt<'tcx> { /// Like [Self::canonicalize_query], but preserves distinct universes. For /// example, canonicalizing `&'?0: Trait<'?1>`, where `'?0` is in `U1` and - /// `'?1` is in `U3` would be canonicalized to have ?0` in `U1` and `'?1` + /// `'?1` is in `U3` would be canonicalized to have `?0` in `U1` and `'?1` /// in `U2`. /// /// This is used for Chalk integration. diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 8c782a933a5..ce230afdab3 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -30,7 +30,7 @@ use rustc_middle::ty::{self, List, TyCtxt}; use rustc_span::source_map::Span; pub use rustc_middle::infer::canonical::*; -use substitute::CanonicalExt; +pub use substitute::CanonicalExt; mod canonicalizer; pub mod query_response; @@ -100,7 +100,11 @@ impl<'tcx> InferCtxt<'tcx> { /// variable for it. If this is an existentially quantified /// variable, then you'll get a new inference variable; if it is a /// universally quantified variable, you get a placeholder. - fn instantiate_canonical_var( + /// + /// FIXME(-Ztrait-solver=next): This is public because it's used by the + /// new trait solver which has a different canonicalization routine. + /// We should somehow deduplicate all of this. + pub fn instantiate_canonical_var( &self, span: Span, cv_info: CanonicalVarInfo<'tcx>, diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 832af91a431..436d29c2449 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -151,11 +151,21 @@ impl<'tcx> InferCtxt<'tcx> { }) } - /// FIXME: This method should only be used for canonical queries and therefore be private. - /// - /// As the new solver does canonicalization slightly differently, this is also used there - /// for now. This should hopefully change fairly soon. - pub fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { + /// Used by the new solver as that one takes the opaque types at the end of a probe + /// to deal with multiple candidates without having to recompute them. + pub fn clone_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { + self.inner + .borrow() + .opaque_type_storage + .opaque_types + .iter() + .map(|&(k, ref v)| { + (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty) + }) + .collect() + } + + fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types) .into_iter() .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)) diff --git a/compiler/rustc_infer/src/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/substitute.rs index c5c6fc41b9e..cac3b407251 100644 --- a/compiler/rustc_infer/src/infer/canonical/substitute.rs +++ b/compiler/rustc_infer/src/infer/canonical/substitute.rs @@ -11,7 +11,9 @@ use rustc_middle::ty::fold::{FnMutDelegate, TypeFoldable}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, TyCtxt}; -pub(super) trait CanonicalExt<'tcx, V> { +/// FIXME(-Ztrait-solver=next): This or public because it is shared with the +/// new trait solver implementation. We should deduplicate canonicalization. +pub trait CanonicalExt<'tcx, V> { /// Instantiate the wrapped value, replacing each canonical value /// with the value given in `var_values`. fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 79efc1ce7bf..bf6af57c66a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1690,7 +1690,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { format!("{name} is defined in the current crate") } else { let crate_name = self.tcx.crate_name(defid.krate); - format!("{name} is defined in crate `{crate_name}") + format!("{name} is defined in crate `{crate_name}`") }; diagnostic.span_note(def_span, msg); }; diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index a499018d3a2..2c480355085 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -70,7 +70,7 @@ pub enum RegionResolutionError<'tcx> { /// `o` requires that `a <= b`, but this does not hold ConcreteFailure(SubregionOrigin<'tcx>, Region<'tcx>, Region<'tcx>), - /// `GenericBoundFailure(p, s, a) + /// `GenericBoundFailure(p, s, a)`: /// /// The parameter/associated-type `p` must be known to outlive the lifetime /// `a` (but none of the known bounds are sufficient). diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 6e413a7f412..573cd91a2a2 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -50,7 +50,7 @@ where /// /// - Covariant means `a <: b`. /// - Contravariant means `b <: a`. - /// - Invariant means `a == b. + /// - Invariant means `a == b`. /// - Bivariant means that it doesn't matter. ambient_variance: ty::Variance, diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 33514eedfc3..872f617474c 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -249,7 +249,7 @@ pub enum VerifyBound<'tcx> { /// in that case we can show `'b: 'c`. But if `'?x` winds up being something /// else, the bound isn't relevant. /// -/// In the [`VerifyBound`], this struct is enclosed in `Binder to account +/// In the [`VerifyBound`], this struct is enclosed in `Binder` to account /// for cases like /// /// ```rust diff --git a/compiler/rustc_interface/locales/en-US.ftl b/compiler/rustc_interface/locales/en-US.ftl index da58492ccf2..37994899a20 100644 --- a/compiler/rustc_interface/locales/en-US.ftl +++ b/compiler/rustc_interface/locales/en-US.ftl @@ -33,7 +33,7 @@ interface_rustc_error_fatal = fatal error triggered by #[rustc_error] interface_rustc_error_unexpected_annotation = - unexpected annotation used with `#[rustc_error(...)]! + unexpected annotation used with `#[rustc_error(...)]`! interface_failed_writing_file = failed to write file {$path}: {$error}" diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index e6f04fe0aaa..322ec31fb2c 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -166,15 +166,17 @@ pub enum DocStyle { Inner, } -// Note that the suffix is *not* considered when deciding the `LiteralKind` in -// this type. This means that float literals like `1f32` are classified by this -// type as `Int`. (Compare against `rustc_ast::token::LitKind` and -// `rustc_ast::ast::LitKind.) +/// Enum representing the literal types supported by the lexer. +/// +/// Note that the suffix is *not* considered when deciding the `LiteralKind` in +/// this type. This means that float literals like `1f32` are classified by this +/// type as `Int`. (Compare against `rustc_ast::token::LitKind` and +/// `rustc_ast::ast::LitKind`). #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum LiteralKind { /// "12_u8", "0o100", "0b120i99", "1f32". Int { base: Base, empty_int: bool }, - /// "12.34f32", "1e3", but not "1f32`. + /// "12.34f32", "1e3", but not "1f32". Float { base: Base, empty_exponent: bool }, /// "'a'", "'\\'", "'''", "';" Char { terminated: bool }, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 59540aaf18f..5b2100b5da9 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1288,7 +1288,7 @@ declare_lint! { } declare_lint_pass!( - /// Explains corresponding feature flag must be enabled for the `#[track_caller] attribute to + /// Explains corresponding feature flag must be enabled for the `#[track_caller]` attribute to /// do anything UngatedAsyncFnTrackCaller => [UNGATED_ASYNC_FN_TRACK_CALLER] ); diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 0a42265a6ba..4761ce83fab 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -9,7 +9,6 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" -#include "llvm/InitializePasses.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/AssemblyAnnotationWriter.h" #include "llvm/IR/IntrinsicInst.h" @@ -58,22 +57,6 @@ typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef; DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef) DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) -extern "C" void LLVMInitializePasses() { - PassRegistry &Registry = *PassRegistry::getPassRegistry(); - initializeCore(Registry); - initializeCodeGen(Registry); - initializeScalarOpts(Registry); - initializeVectorization(Registry); - initializeIPO(Registry); - initializeAnalysis(Registry); - initializeTransformUtils(Registry); - initializeInstCombine(Registry); -#if LLVM_VERSION_LT(16, 0) - initializeInstrumentation(Registry); -#endif - initializeTarget(Registry); -} - extern "C" void LLVMTimeTraceProfilerInitialize() { timeTraceProfilerInitialize( /* TimeTraceGranularity */ 0, @@ -1004,23 +987,8 @@ LLVMRustPrintModule(LLVMModuleRef M, const char *Path, DemangleFn Demangle) { } extern "C" void LLVMRustPrintPasses() { - LLVMInitializePasses(); - struct MyListener : PassRegistrationListener { - void passEnumerate(const PassInfo *Info) { - StringRef PassArg = Info->getPassArgument(); - StringRef PassName = Info->getPassName(); - if (!PassArg.empty()) { - // These unsigned->signed casts could theoretically overflow, but - // realistically never will (and even if, the result is implementation - // defined rather plain UB). - printf("%15.*s - %.*s\n", (int)PassArg.size(), PassArg.data(), - (int)PassName.size(), PassName.data()); - } - } - } Listener; - - PassRegistry *PR = PassRegistry::getPassRegistry(); - PR->enumerateWith(&Listener); + PassBuilder PB; + PB.printPassNames(outs()); } extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols, diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index ccb07804b96..3ab01f7809b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1621,7 +1621,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn encode_info_for_closure(&mut self, def_id: LocalDefId) { // NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic, - // including on the signature, which is inferred in `typeck. + // including on the signature, which is inferred in `typeck`. let typeck_result: &'tcx ty::TypeckResults<'tcx> = self.tcx.typeck(def_id); let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); let ty = typeck_result.node_type(hir_id); diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 8712514a384..7f8fc17744d 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -123,6 +123,11 @@ impl<'tcx> CanonicalVarInfo<'tcx> { self.kind.universe() } + #[must_use] + pub fn with_updated_universe(self, ui: ty::UniverseIndex) -> CanonicalVarInfo<'tcx> { + CanonicalVarInfo { kind: self.kind.with_updated_universe(ui) } + } + pub fn is_existential(&self) -> bool { match self.kind { CanonicalVarKind::Ty(_) => true, @@ -133,6 +138,28 @@ impl<'tcx> CanonicalVarInfo<'tcx> { CanonicalVarKind::PlaceholderConst(_, _) => false, } } + + pub fn is_region(&self) -> bool { + match self.kind { + CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true, + CanonicalVarKind::Ty(_) + | CanonicalVarKind::PlaceholderTy(_) + | CanonicalVarKind::Const(_, _) + | CanonicalVarKind::PlaceholderConst(_, _) => false, + } + } + + pub fn expect_anon_placeholder(self) -> u32 { + match self.kind { + CanonicalVarKind::Ty(_) + | CanonicalVarKind::Region(_) + | CanonicalVarKind::Const(_, _) => bug!("expected placeholder: {self:?}"), + + CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.name.expect_anon(), + CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.name.expect_anon(), + CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.name.as_u32(), + } + } } /// Describes the "kind" of the canonical variable. This is a "kind" @@ -177,6 +204,38 @@ impl<'tcx> CanonicalVarKind<'tcx> { CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.universe, } } + + /// Replaces the universe of this canonical variable with `ui`. + /// + /// In case this is a float or int variable, this causes an ICE if + /// the updated universe is not the root. + pub fn with_updated_universe(self, ui: ty::UniverseIndex) -> CanonicalVarKind<'tcx> { + match self { + CanonicalVarKind::Ty(kind) => match kind { + CanonicalTyVarKind::General(_) => { + CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) + } + CanonicalTyVarKind::Int | CanonicalTyVarKind::Float => { + assert_eq!(ui, ty::UniverseIndex::ROOT); + CanonicalVarKind::Ty(kind) + } + }, + CanonicalVarKind::PlaceholderTy(placeholder) => { + CanonicalVarKind::PlaceholderTy(ty::Placeholder { universe: ui, ..placeholder }) + } + CanonicalVarKind::Region(_) => CanonicalVarKind::Region(ui), + CanonicalVarKind::PlaceholderRegion(placeholder) => { + CanonicalVarKind::PlaceholderRegion(ty::Placeholder { universe: ui, ..placeholder }) + } + CanonicalVarKind::Const(_, ty) => CanonicalVarKind::Const(ui, ty), + CanonicalVarKind::PlaceholderConst(placeholder, ty) => { + CanonicalVarKind::PlaceholderConst( + ty::Placeholder { universe: ui, ..placeholder }, + ty, + ) + } + } + } } /// Rust actually has more than one category of type variables; @@ -213,7 +272,8 @@ pub struct QueryResponse<'tcx, R> { pub value: R, } -#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct QueryRegionConstraints<'tcx> { pub outlives: Vec>, pub member_constraints: Vec>, diff --git a/compiler/rustc_middle/src/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs index 38868c21049..2db59f37f40 100644 --- a/compiler/rustc_middle/src/infer/mod.rs +++ b/compiler/rustc_middle/src/infer/mod.rs @@ -12,7 +12,8 @@ use rustc_span::Span; /// ```text /// R0 member of [O1..On] /// ``` -#[derive(Debug, Clone, HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct MemberConstraint<'tcx> { /// The `DefId` and substs of the opaque type causing this constraint. /// Used for error reporting. diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 0d78c6135b3..99cdb769da1 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2908,7 +2908,7 @@ fn pretty_print_const_value<'tcx>( // the `destructure_const` query with an empty `ty::ParamEnv` without // introducing ICEs (e.g. via `layout_of`) from missing bounds. // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized` - // to be able to destructure the tuple into `(0u8, *mut T) + // to be able to destructure the tuple into `(0u8, *mut T)` // // FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the // correct `ty::ParamEnv` to allow printing *all* constant values. diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index 1610ae1ce14..28a3b51b7fc 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -11,7 +11,7 @@ use std::io::{self, Write}; pub const TOOLTIP_INDENT: &str = " "; const CARET: char = '\u{2038}'; // Unicode `CARET` -const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT BINDING BRACKET +const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT BINDING BRACKET` const ANNOTATION_RIGHT_BRACKET: char = '\u{2989}'; // Unicode `Z NOTATION LEFT BINDING BRACKET` const NEW_LINE_SPAN: &str = "\n"; const HEADER: &str = r#" diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 51feae3cf8a..5133da3429a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1672,7 +1672,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. + /// See `rustc_resolve::late::lifetimes` for details. query resolve_bound_vars(_: hir::OwnerId) -> &'tcx ResolveBoundVars { arena_cache desc { "resolving lifetimes" } diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index c5bf9717f03..bd43867a3da 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -2,6 +2,7 @@ use std::ops::ControlFlow; use rustc_data_structures::intern::Interned; +use crate::infer::canonical::QueryRegionConstraints; use crate::ty::{ FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, }; @@ -18,20 +19,25 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { } /// Additional constraints returned on success. -#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)] +#[derive(Debug, PartialEq, Eq, Clone, Hash, Default, TypeFoldable, TypeVisitable)] pub struct ExternalConstraintsData<'tcx> { // FIXME: implement this. - pub regions: (), + pub region_constraints: QueryRegionConstraints<'tcx>, pub opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>, } +// FIXME: Having to clone `region_constraints` for folding feels bad and +// probably isn't great wrt performance. +// +// Not sure how to fix this, maybe we should also intern `opaque_types` and +// `region_constraints` here or something. impl<'tcx> TypeFoldable> for ExternalConstraints<'tcx> { fn try_fold_with>>( self, folder: &mut F, ) -> Result { Ok(FallibleTypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData { - regions: (), + region_constraints: self.region_constraints.clone().try_fold_with(folder)?, opaque_types: self .opaque_types .iter() @@ -42,7 +48,7 @@ impl<'tcx> TypeFoldable> for ExternalConstraints<'tcx> { fn fold_with>>(self, folder: &mut F) -> Self { TypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData { - regions: (), + region_constraints: self.region_constraints.clone().fold_with(folder), opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(), }) } @@ -53,7 +59,7 @@ impl<'tcx> TypeVisitable> for ExternalConstraints<'tcx> { &self, visitor: &mut V, ) -> std::ops::ControlFlow { - self.regions.visit_with(visitor)?; + self.region_constraints.visit_with(visitor)?; self.opaque_types.visit_with(visitor)?; ControlFlow::Continue(()) } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 884ae7f5da2..527ec9f6e1c 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -16,7 +16,7 @@ pub use int::*; pub use kind::*; pub use valtree::*; -/// Use this rather than `ConstData, whenever possible. +/// Use this rather than `ConstData`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_pass_by_value] pub struct Const<'tcx>(pub(super) Interned<'tcx, ConstData<'tcx>>); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0333198c203..e9e121f9c9b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -310,7 +310,7 @@ pub struct CommonLifetimes<'tcx> { pub re_vars: Vec>, /// Pre-interned values of the form: - /// `ReLateBound(DebruijnIndex(i), BoundRegion { var: v, kind: BrAnon(v, None) }) + /// `ReLateBound(DebruijnIndex(i), BoundRegion { var: v, kind: BrAnon(v, None) })` /// for small values of `i` and `v`. pub re_late_bounds: Vec>>, } @@ -2187,7 +2187,7 @@ impl<'tcx> TyCtxt<'tcx> { // Actually intern type lists as lists of `GenericArg`s. // // Transmuting from `Ty<'tcx>` to `GenericArg<'tcx>` is sound - // as explained in ty_slice_as_generic_arg`. With this, + // as explained in `ty_slice_as_generic_arg`. With this, // we guarantee that even when transmuting between `List>` // and `List>`, the uniqueness requirement for // lists is upheld. @@ -2450,7 +2450,7 @@ impl<'tcx> TyCtxtAt<'tcx> { self.tcx.ty_error_with_message(self.span, "TyKind::Error constructed but no error reported") } - /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg to + /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to /// ensure it gets used. #[track_caller] pub fn ty_error_with_message(self, msg: &str) -> Ty<'tcx> { diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 355b8d8b431..92a040068dd 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -105,7 +105,7 @@ impl<'tcx> VariantDef { impl<'tcx> Ty<'tcx> { pub fn inhabited_predicate(self, tcx: TyCtxt<'tcx>) -> InhabitedPredicate<'tcx> { match self.kind() { - // For now, union`s are always considered inhabited + // For now, unions are always considered inhabited Adt(adt, _) if adt.is_union() => InhabitedPredicate::True, // Non-exhaustive ADTs from other crates are always considered inhabited Adt(adt, _) if adt.is_variant_list_non_exhaustive() && !adt.did().is_local() => { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 090272a6fa6..9a517d2d2b4 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -93,7 +93,7 @@ impl IntegerExt for Integer { if discr < fit { bug!( "Integer::repr_discr: `#[repr]` hint too small for \ - discriminant range of enum `{}", + discriminant range of enum `{}`", ty ) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 5df01b8abc3..dce18a5850f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -710,7 +710,7 @@ impl<'tcx> Predicate<'tcx> { // The substitution from the input trait-ref is therefore going to be // `'a => 'x` (where `'x` has a DB index of 1). // - The supertrait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an - // early-bound parameter and `'b' is a late-bound parameter with a + // early-bound parameter and `'b` is a late-bound parameter with a // DB index of 1. // - If we replace `'a` with `'x` from the input, it too will have // a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>` @@ -2444,7 +2444,7 @@ impl<'tcx> TyCtxt<'tcx> { None } - /// Check if the given `DefId` is `#\[automatically_derived\], *and* + /// Check if the given `DefId` is `#\[automatically_derived\]`, *and* /// whether it was produced by expanding a builtin derive macro. pub fn is_builtin_derived(self, def_id: DefId) -> bool { if self.is_automatically_derived(def_id) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index ba714541c9e..e6a73e8bb1c 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -107,6 +107,15 @@ impl BoundRegionKind { _ => None, } } + + pub fn expect_anon(&self) -> u32 { + match *self { + BoundRegionKind::BrNamed(_, _) | BoundRegionKind::BrEnv => { + bug!("expected anon region: {self:?}") + } + BoundRegionKind::BrAnon(idx, _) => idx, + } + } } pub trait Article { diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 2f63333d46b..cfacb5ea327 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -55,7 +55,7 @@ pub fn as_constant_inner<'tcx>( ConstantKind::Ty(tcx.const_error_with_guaranteed(ty, guar)) } Err(LitToConstError::TypeError) => { - bug!("encountered type error in `lit_to_mir_constant") + bug!("encountered type error in `lit_to_mir_constant`") } }; diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index fa5f392fa74..536745d2cfe 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -74,7 +74,7 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> { // // `unsafe { *FOO = 0; *BAR.field = 1; }` // `unsafe { &mut *FOO }` - // `unsafe { (*ARRAY)[0] = val; } + // `unsafe { (*ARRAY)[0] = val; }` if !place.projection.iter().any(|p| matches!(p, PlaceElem::Deref)) { let source_info = self.body.source_info(location); let lint_root = self.body.source_scopes[source_info.scope] diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index f973c1ed28f..8ee316773ae 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -407,7 +407,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { if self.prev().is_macro_expansion() && self.curr().is_macro_expansion() { // Macros that expand to include branching (such as // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or - // `trace!()) typically generate callee spans with identical + // `trace!()`) typically generate callee spans with identical // ranges (typically the full span of the macro) for all // `BasicBlocks`. This makes it impossible to distinguish // the condition (`if val1 != val2`) from the optional @@ -694,7 +694,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { /// `prev.span.hi()` will be greater than (further right of) `prev_original_span.hi()`. /// If prev.span() was split off to the right of a closure, prev.span().lo() will be /// greater than prev_original_span.lo(). The actual span of `prev_original_span` is - /// not as important as knowing that `prev()` **used to have the same span** as `curr(), + /// not as important as knowing that `prev()` **used to have the same span** as `curr()`, /// which means their sort order is still meaningful for determining the dominator /// relationship. /// diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 4193eb7d6e8..cdd28ae0c01 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -248,7 +248,7 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> // N.B., this `borrow()` is guaranteed to be valid (i.e., the value // cannot yet be stolen), because `mir_promoted()`, which steals - // from `mir_const(), forces this query to execute before + // from `mir_const()`, forces this query to execute before // performing the steal. let body = &tcx.mir_const(def).borrow(); diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index 2f02d00ec9f..c6e7468aab4 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -68,8 +68,11 @@ fn lower_slice_len_call<'tcx>( ty::FnDef(fn_def_id, _) if fn_def_id == &slice_len_fn_item_def_id => { // perform modifications // from something like `_5 = core::slice::::len(move _6) -> bb1` - // into `_5 = Len(*_6) + // into: + // ``` + // _5 = Len(*_6) // goto bb1 + // ``` // make new RValue for Len let deref_arg = tcx.mk_place_deref(arg); diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index dbd3b76786f..b0ab0f10624 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -134,11 +134,11 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { // Process the replace ranges, starting from the highest start // position and working our way back. If have tokens like: // - // `#[cfg(FALSE)]` struct Foo { #[cfg(FALSE)] field: bool }` + // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }` // // Then we will generate replace ranges for both // the `#[cfg(FALSE)] field: bool` and the entire - // `#[cfg(FALSE)]` struct Foo { #[cfg(FALSE)] field: bool }` + // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }` // // By starting processing from the replace range with the greatest // start position, we ensure that any replace range which encloses diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index b1b79fe4e05..da82e4724d1 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -335,7 +335,7 @@ impl TokenCursor { num_of_hashes = cmp::max(num_of_hashes, count); } - // `/// foo` becomes `doc = r"foo". + // `/// foo` becomes `doc = r"foo"`. let delim_span = DelimSpan::from_single(span); let body = TokenTree::Delimited( delim_span, diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 51a19c8e3c0..5e2d2d3e5a7 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -646,7 +646,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { } // `UseTree` has one inline use (in `ast::ItemKind::Use`) and one - // non-inline use (in `ast::UseTreeKind::Nested). The former case is more + // non-inline use (in `ast::UseTreeKind::Nested`). The former case is more // common, so we don't implement `visit_use_tree` and tolerate the missed // coverage in the latter case. diff --git a/compiler/rustc_passes/src/liveness/rwu_table.rs b/compiler/rustc_passes/src/liveness/rwu_table.rs index 6d5983f53dc..053bf5c234a 100644 --- a/compiler/rustc_passes/src/liveness/rwu_table.rs +++ b/compiler/rustc_passes/src/liveness/rwu_table.rs @@ -9,7 +9,7 @@ pub(super) struct RWU { } /// Conceptually, this is like a `Vec>`. But the number of -/// RWU`s can get very large, so it uses a more compact representation. +/// RWU's can get very large, so it uses a more compact representation. pub(super) struct RWUTable { /// Total number of live nodes. live_nodes: usize, diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 70c481fb0ee..46e34462cf2 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -333,7 +333,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { }, ); - // `Encode the file footer. + // Encode the file footer. let footer_pos = encoder.position() as u64; encoder.encode_tagged( TAG_FILE_FOOTER, diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index ba7f04239c3..52f0b65fad6 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -368,7 +368,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during /// expansion and import resolution (perhaps they can be merged in the future). /// The function is used for resolving initial segments of macro paths (e.g., `foo` in - /// `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition. + /// `foo::bar!();` or `foo!();`) and also for import paths on 2018 edition. #[instrument(level = "debug", skip(self, scope_set))] pub(crate) fn early_resolve_ident_in_lexical_scope( &mut self, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 36415936bdc..b8ddc455257 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -878,7 +878,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ); let is_assoc_fn = self.self_type_is_available(); if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function { - // The current function has a `self' parameter, but we were unable to resolve + // The current function has a `self` parameter, but we were unable to resolve // a reference to `self`. This can only happen if the `self` identifier we // are resolving came from a different hygiene context. if fn_kind.decl().inputs.get(0).map_or(false, |p| p.is_self()) { diff --git a/compiler/rustc_session/locales/en-US.ftl b/compiler/rustc_session/locales/en-US.ftl index fe553edab42..ff53f22d43f 100644 --- a/compiler/rustc_session/locales/en-US.ftl +++ b/compiler/rustc_session/locales/en-US.ftl @@ -5,7 +5,7 @@ session_incorrect_cgu_reuse_type = }`{$expected_reuse}` session_cgu_not_recorded = - CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded` + CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded session_feature_gate_error = {$explain} diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 295e93f6103..d4e4ace889b 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2245,7 +2245,7 @@ pub fn parse_externs( early_error( error_format, "the `-Z unstable-options` flag must also be passed to \ - enable `--extern options", + enable `--extern` options", ); } for opt in opts.split(',') { @@ -2792,7 +2792,7 @@ pub enum PpMode { HirTree, /// `-Zunpretty=thir-tree` ThirTree, - /// `-Zunpretty=`thir-flat` + /// `-Zunpretty=thir-flat` ThirFlat, /// `-Zunpretty=mir` Mir, diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 2340d501d5a..162c15574b5 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -235,7 +235,7 @@ impl Decodable for DefIndex { pub struct DefId { // cfg-ing the order of fields so that the `DefIndex` which is high entropy always ends up in // the lower bits no matter the endianness. This allows the compiler to turn that `Hash` impl - // into a direct call to 'u64::hash(_)`. + // into a direct call to `u64::hash(_)`. #[cfg(not(all(target_pointer_width = "64", target_endian = "big")))] pub index: DefIndex, pub krate: CrateNum, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index fb579e4ff77..6272bf7f25e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1954,7 +1954,7 @@ impl Interner { let name = Symbol::new(inner.strings.len() as u32); // SAFETY: we convert from `&str` to `&[u8]`, clone it into the arena, - // and immediately convert the clone back to `&[u8], all because there + // and immediately convert the clone back to `&[u8]`, all because there // is no `inner.arena.alloc_str()` method. This is clearly safe. let string: &str = unsafe { str::from_utf8_unchecked(inner.arena.alloc_slice(string.as_bytes())) }; diff --git a/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs new file mode 100644 index 00000000000..c048d4a2aad --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs @@ -0,0 +1,390 @@ +use std::cmp::Ordering; + +use crate::infer::InferCtxt; +use rustc_middle::infer::canonical::Canonical; +use rustc_middle::infer::canonical::CanonicalTyVarKind; +use rustc_middle::infer::canonical::CanonicalVarInfo; +use rustc_middle::infer::canonical::CanonicalVarInfos; +use rustc_middle::infer::canonical::CanonicalVarKind; +use rustc_middle::ty::BoundRegionKind::BrAnon; +use rustc_middle::ty::BoundTyKind; +use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::TypeVisitableExt; +use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{TypeFoldable, TypeFolder, TypeSuperFoldable}; + +/// Whether we're canonicalizing a query input or the query reponse. +/// +/// When canonicalizing an input we're in the context of the caller +/// while canonicalizing the response happens in the context of the +/// query. +#[derive(Debug, Clone, Copy)] +pub enum CanonicalizeMode { + Input, + /// FIXME: We currently return region constraints refering to + /// placeholders and inference variables from a binder instantiated + /// inside of the query. + /// + /// In the long term we should eagerly deal with these constraints + /// inside of the query and only propagate constraints which are + /// actually nameable by the caller. + Response { + /// The highest universe nameable by the caller. + /// + /// All variables in a universe nameable by the caller get mapped + /// to the root universe in the response and then mapped back to + /// their correct universe when applying the query response in the + /// context of the caller. + /// + /// This doesn't work for universes created inside of the query so + /// we do remember their universe in the response. + max_input_universe: ty::UniverseIndex, + }, +} + +pub struct Canonicalizer<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, + canonicalize_mode: CanonicalizeMode, + + variables: &'a mut Vec>, + primitive_var_infos: Vec>, + binder_index: ty::DebruijnIndex, +} + +impl<'a, 'tcx> Canonicalizer<'a, 'tcx> { + #[instrument(level = "debug", skip(infcx), ret)] + pub fn canonicalize>>( + infcx: &'a InferCtxt<'tcx>, + canonicalize_mode: CanonicalizeMode, + variables: &'a mut Vec>, + value: T, + ) -> Canonical<'tcx, T> { + let mut canonicalizer = Canonicalizer { + infcx, + canonicalize_mode, + + variables, + primitive_var_infos: Vec::new(), + binder_index: ty::INNERMOST, + }; + + let value = value.fold_with(&mut canonicalizer); + assert!(!value.needs_infer()); + assert!(!value.has_placeholders()); + + let (max_universe, variables) = canonicalizer.finalize(); + + Canonical { max_universe, variables, value } + } + + fn finalize(self) -> (ty::UniverseIndex, CanonicalVarInfos<'tcx>) { + let mut var_infos = self.primitive_var_infos; + // See the rustc-dev-guide section about how we deal with universes + // during canonicalization in the new solver. + match self.canonicalize_mode { + // We try to deduplicate as many query calls as possible and hide + // all information which should not matter for the solver. + // + // For this we compress universes as much as possible. + CanonicalizeMode::Input => {} + // When canonicalizing a response we map a universes already entered + // by the caller to the root universe and only return useful universe + // information for placeholders and inference variables created inside + // of the query. + CanonicalizeMode::Response { max_input_universe } => { + for var in var_infos.iter_mut() { + let uv = var.universe(); + let new_uv = ty::UniverseIndex::from( + uv.index().saturating_sub(max_input_universe.index()), + ); + *var = var.with_updated_universe(new_uv); + } + let max_universe = var_infos + .iter() + .map(|info| info.universe()) + .max() + .unwrap_or(ty::UniverseIndex::ROOT); + + let var_infos = self.infcx.tcx.mk_canonical_var_infos(&var_infos); + return (max_universe, var_infos); + } + } + + // Given a `var_infos` with existentials `En` and universals `Un` in + // universes `n`, this algorithm compresses them in place so that: + // + // - the new universe indices are as small as possible + // - we only create a new universe if we would otherwise put a placeholder in + // the same compressed universe as an existential which cannot name it + // + // Let's walk through an example: + // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 0 + // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 1 + // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 1, next_orig_uv: 2 + // - var_infos: [E0, U1, E5, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 5 + // - var_infos: [E0, U1, E1, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 6 + // - var_infos: [E0, U1, E1, U1, E1, E2, U2], curr_compressed_uv: 2, next_orig_uv: - + // + // This algorithm runs in `O(n²)` where `n` is the number of different universe + // indices in the input. This should be fine as `n` is expected to be small. + let mut curr_compressed_uv = ty::UniverseIndex::ROOT; + let mut existential_in_new_uv = false; + let mut next_orig_uv = Some(ty::UniverseIndex::ROOT); + while let Some(orig_uv) = next_orig_uv.take() { + let mut update_uv = |var: &mut CanonicalVarInfo<'tcx>, orig_uv, is_existential| { + let uv = var.universe(); + match uv.cmp(&orig_uv) { + Ordering::Less => (), // Already updated + Ordering::Equal => { + if is_existential { + existential_in_new_uv = true; + } else if existential_in_new_uv { + // `var` is a placeholder from a universe which is not nameable + // by an existential which we already put into the compressed + // universe `curr_compressed_uv`. We therefore have to create a + // new universe for `var`. + curr_compressed_uv = curr_compressed_uv.next_universe(); + existential_in_new_uv = false; + } + + *var = var.with_updated_universe(curr_compressed_uv); + } + Ordering::Greater => { + // We can ignore this variable in this iteration. We only look at + // universes which actually occur in the input for performance. + // + // For this we set `next_orig_uv` to the next smallest, not yet compressed, + // universe of the input. + if next_orig_uv.map_or(true, |curr_next_uv| uv.cannot_name(curr_next_uv)) { + next_orig_uv = Some(uv); + } + } + } + }; + + // For each universe which occurs in the input, we first iterate over all + // placeholders and then over all inference variables. + // + // Whenever we compress the universe of a placeholder, no existential with + // an already compressed universe can name that placeholder. + for is_existential in [false, true] { + for var in var_infos.iter_mut() { + // We simply put all regions from the input into the highest + // compressed universe, so we only deal with them at the end. + if !var.is_region() { + if is_existential == var.is_existential() { + update_uv(var, orig_uv, is_existential) + } + } + } + } + } + + for var in var_infos.iter_mut() { + if var.is_region() { + assert!(var.is_existential()); + *var = var.with_updated_universe(curr_compressed_uv); + } + } + + let var_infos = self.infcx.tcx.mk_canonical_var_infos(&var_infos); + (curr_compressed_uv, var_infos) + } +} + +impl<'tcx> TypeFolder> for Canonicalizer<'_, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_binder(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T> + where + T: TypeFoldable>, + { + self.binder_index.shift_in(1); + let t = t.super_fold_with(self); + self.binder_index.shift_out(1); + t + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + let r = self.infcx.shallow_resolve(r); + let kind = match *r { + ty::ReLateBound(..) => return r, + + ty::ReStatic => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Response { .. } => return r, + }, + + ty::ReErased | ty::ReFree(_) | ty::ReEarlyBound(_) => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Response { .. } => bug!("unexpected region in response: {r:?}"), + }, + + ty::RePlaceholder(placeholder) => match self.canonicalize_mode { + // We canonicalize placeholder regions as existentials in query inputs. + CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Response { max_input_universe } => { + // If we have a placeholder region inside of a query, it must be from + // a new universe. + if max_input_universe.can_name(placeholder.universe) { + bug!("new placeholder in universe {max_input_universe:?}: {r:?}"); + } + CanonicalVarKind::PlaceholderRegion(placeholder) + } + }, + + ty::ReVar(_) => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Response { .. } => { + CanonicalVarKind::Region(self.infcx.universe_of_region(r)) + } + }, + + ty::ReError(_) => return r, + }; + + let existing_bound_var = match self.canonicalize_mode { + CanonicalizeMode::Input => None, + CanonicalizeMode::Response { .. } => { + self.variables.iter().position(|&v| v == r.into()).map(ty::BoundVar::from) + } + }; + let var = existing_bound_var.unwrap_or_else(|| { + let var = ty::BoundVar::from(self.variables.len()); + self.variables.push(r.into()); + self.primitive_var_infos.push(CanonicalVarInfo { kind }); + var + }); + let br = ty::BoundRegion { var, kind: BrAnon(var.as_u32(), None) }; + self.interner().mk_re_late_bound(self.binder_index, br) + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + let kind = match *t.kind() { + ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) { + Ok(t) => return self.fold_ty(t), + Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)), + }, + ty::Infer(ty::IntVar(_)) => { + let nt = self.infcx.shallow_resolve(t); + if nt != t { + return self.fold_ty(nt); + } else { + CanonicalVarKind::Ty(CanonicalTyVarKind::Int) + } + } + ty::Infer(ty::FloatVar(_)) => { + let nt = self.infcx.shallow_resolve(t); + if nt != t { + return self.fold_ty(nt); + } else { + CanonicalVarKind::Ty(CanonicalTyVarKind::Int) + } + } + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("fresh var during canonicalization: {t:?}") + } + ty::Placeholder(placeholder) => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::PlaceholderTy(ty::Placeholder { + universe: placeholder.universe, + name: BoundTyKind::Anon(self.variables.len() as u32), + }), + CanonicalizeMode::Response { .. } => CanonicalVarKind::PlaceholderTy(placeholder), + }, + ty::Param(_) => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::PlaceholderTy(ty::Placeholder { + universe: ty::UniverseIndex::ROOT, + name: ty::BoundTyKind::Anon(self.variables.len() as u32), + }), + CanonicalizeMode::Response { .. } => bug!("param ty in response: {t:?}"), + }, + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Dynamic(_, _, _) + | ty::Closure(_, _) + | ty::Generator(_, _, _) + | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) + | ty::Never + | ty::Tuple(_) + | ty::Alias(_, _) + | ty::Bound(_, _) + | ty::Error(_) => return t.super_fold_with(self), + }; + + let var = ty::BoundVar::from( + self.variables.iter().position(|&v| v == t.into()).unwrap_or_else(|| { + let var = self.variables.len(); + self.variables.push(t.into()); + self.primitive_var_infos.push(CanonicalVarInfo { kind }); + var + }), + ); + let bt = ty::BoundTy { var, kind: BoundTyKind::Anon(var.index() as u32) }; + self.interner().mk_bound(self.binder_index, bt) + } + + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { + let kind = match c.kind() { + ty::ConstKind::Infer(ty::InferConst::Var(vid)) => match self.infcx.probe_const_var(vid) + { + Ok(c) => return self.fold_const(c), + Err(universe) => CanonicalVarKind::Const(universe, c.ty()), + }, + ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => { + bug!("fresh var during canonicalization: {c:?}") + } + ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst( + ty::Placeholder { + universe: placeholder.universe, + name: ty::BoundVar::from(self.variables.len()), + }, + c.ty(), + ), + CanonicalizeMode::Response { .. } => { + CanonicalVarKind::PlaceholderConst(placeholder, c.ty()) + } + }, + ty::ConstKind::Param(_) => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst( + ty::Placeholder { + universe: ty::UniverseIndex::ROOT, + name: ty::BoundVar::from(self.variables.len()), + }, + c.ty(), + ), + CanonicalizeMode::Response { .. } => bug!("param ty in response: {c:?}"), + }, + ty::ConstKind::Bound(_, _) + | ty::ConstKind::Unevaluated(_) + | ty::ConstKind::Value(_) + | ty::ConstKind::Error(_) + | ty::ConstKind::Expr(_) => return c.super_fold_with(self), + }; + + let var = ty::BoundVar::from( + self.variables.iter().position(|&v| v == c.into()).unwrap_or_else(|| { + let var = self.variables.len(); + self.variables.push(c.into()); + self.primitive_var_infos.push(CanonicalVarInfo { kind }); + var + }), + ); + self.interner().mk_const(ty::ConstKind::Bound(self.binder_index, var), c.ty()) + } +} diff --git a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs new file mode 100644 index 00000000000..8c3be8da16b --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs @@ -0,0 +1,240 @@ +/// Canonicalization is used to separate some goal from its context, +/// throwing away unnecessary information in the process. +/// +/// This is necessary to cache goals containing inference variables +/// and placeholders without restricting them to the current `InferCtxt`. +/// +/// Canonicalization is fairly involved, for more details see the relevant +/// section of the [rustc-dev-guide][c]. +/// +/// [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html +use self::canonicalize::{CanonicalizeMode, Canonicalizer}; +use super::{CanonicalGoal, Certainty, EvalCtxt, Goal}; +use super::{CanonicalResponse, ExternalConstraints, QueryResult, Response}; +use rustc_infer::infer::canonical::query_response::make_query_region_constraints; +use rustc_infer::infer::canonical::CanonicalVarValues; +use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; +use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::solve::ExternalConstraintsData; +use rustc_infer::traits::ObligationCause; +use rustc_middle::ty::{self, GenericArgKind}; +use rustc_span::DUMMY_SP; +use std::iter; +use std::ops::Deref; + +mod canonicalize; + +impl<'tcx> EvalCtxt<'_, 'tcx> { + /// Canonicalizes the goal remembering the original values + /// for each bound variable. + pub(super) fn canonicalize_goal( + &self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + ) -> (Vec>, CanonicalGoal<'tcx>) { + let mut orig_values = Default::default(); + let canonical_goal = Canonicalizer::canonicalize( + self.infcx, + CanonicalizeMode::Input, + &mut orig_values, + goal, + ); + (orig_values, canonical_goal) + } + + /// To return the constraints of a canonical query to the caller, we canonicalize: + /// + /// - `var_values`: a map from bound variables in the canonical goal to + /// the values inferred while solving the instantiated goal. + /// - `external_constraints`: additional constraints which aren't expressable + /// using simple unification of inference variables. + #[instrument(level = "debug", skip(self))] + pub(super) fn make_canonical_response(&self, certainty: Certainty) -> QueryResult<'tcx> { + let external_constraints = self.compute_external_query_constraints()?; + + let response = Response { var_values: self.var_values, external_constraints, certainty }; + let canonical = Canonicalizer::canonicalize( + self.infcx, + CanonicalizeMode::Response { max_input_universe: self.max_input_universe }, + &mut Default::default(), + response, + ); + Ok(canonical) + } + + #[instrument(level = "debug", skip(self), ret)] + fn compute_external_query_constraints(&self) -> Result, NoSolution> { + // Cannot use `take_registered_region_obligations` as we may compute the response + // inside of a `probe` whenever we have multiple choices inside of the solver. + let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); + let region_constraints = self.infcx.with_region_constraints(|region_constraints| { + make_query_region_constraints( + self.tcx(), + region_obligations + .iter() + .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())), + region_constraints, + ) + }); + let opaque_types = self.infcx.clone_opaque_types_for_query_response(); + Ok(self + .tcx() + .mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types })) + } + + /// After calling a canonical query, we apply the constraints returned + /// by the query using this function. + /// + /// This happens in three steps: + /// - we instantiate the bound variables of the query response + /// - we unify the `var_values` of the response with the `original_values` + /// - we apply the `external_constraints` returned by the query + pub(super) fn instantiate_and_apply_query_response( + &mut self, + param_env: ty::ParamEnv<'tcx>, + original_values: Vec>, + response: CanonicalResponse<'tcx>, + ) -> Result { + let substitution = self.compute_query_response_substitution(&original_values, &response); + + let Response { var_values, external_constraints, certainty } = + response.substitute(self.tcx(), &substitution); + + self.unify_query_var_values(param_env, &original_values, var_values)?; + + // FIXME: implement external constraints. + let ExternalConstraintsData { region_constraints, opaque_types: _ } = + external_constraints.deref(); + self.register_region_constraints(region_constraints); + + Ok(certainty) + } + + /// This returns the substitutions to instantiate the bound variables of + /// the canonical reponse. This depends on the `original_values` for the + /// bound variables. + fn compute_query_response_substitution( + &self, + original_values: &[ty::GenericArg<'tcx>], + response: &CanonicalResponse<'tcx>, + ) -> CanonicalVarValues<'tcx> { + // FIXME: Longterm canonical queries should deal with all placeholders + // created inside of the query directly instead of returning them to the + // caller. + let prev_universe = self.infcx.universe(); + let universes_created_in_query = response.max_universe.index() + 1; + for _ in 0..universes_created_in_query { + self.infcx.create_next_universe(); + } + + let var_values = response.value.var_values; + assert_eq!(original_values.len(), var_values.len()); + + // If the query did not make progress with constraining inference variables, + // we would normally create a new inference variables for bound existential variables + // only then unify this new inference variable with the inference variable from + // the input. + // + // We therefore instantiate the existential variable in the canonical response with the + // inference variable of the input right away, which is more performant. + let mut opt_values = vec![None; response.variables.len()]; + for (original_value, result_value) in iter::zip(original_values, var_values.var_values) { + match result_value.unpack() { + GenericArgKind::Type(t) => { + if let &ty::Bound(debruijn, b) = t.kind() { + assert_eq!(debruijn, ty::INNERMOST); + opt_values[b.var.index()] = Some(*original_value); + } + } + GenericArgKind::Lifetime(r) => { + if let ty::ReLateBound(debruijn, br) = *r { + assert_eq!(debruijn, ty::INNERMOST); + opt_values[br.var.index()] = Some(*original_value); + } + } + GenericArgKind::Const(c) => { + if let ty::ConstKind::Bound(debrujin, b) = c.kind() { + assert_eq!(debrujin, ty::INNERMOST); + opt_values[b.index()] = Some(*original_value); + } + } + } + } + + let var_values = self.tcx().mk_substs_from_iter(response.variables.iter().enumerate().map( + |(index, info)| { + if info.universe() != ty::UniverseIndex::ROOT { + // A variable from inside a binder of the query. While ideally these shouldn't + // exist at all (see the FIXME at the start of this method), we have to deal with + // them for now. + self.infcx.instantiate_canonical_var(DUMMY_SP, info, |idx| { + ty::UniverseIndex::from(prev_universe.index() + idx.index()) + }) + } else if info.is_existential() { + // As an optimization we sometimes avoid creating a new inference variable here. + // + // All new inference variables we create start out in the current universe of the caller. + // This is conceptionally wrong as these inference variables would be able to name + // more placeholders then they should be able to. However the inference variables have + // to "come from somewhere", so by equating them with the original values of the caller + // later on, we pull them down into their correct universe again. + if let Some(v) = opt_values[index] { + v + } else { + self.infcx.instantiate_canonical_var(DUMMY_SP, info, |_| prev_universe) + } + } else { + // For placeholders which were already part of the input, we simply map this + // universal bound variable back the placeholder of the input. + original_values[info.expect_anon_placeholder() as usize] + } + }, + )); + + CanonicalVarValues { var_values } + } + + #[instrument(level = "debug", skip(self, param_env), ret)] + fn unify_query_var_values( + &self, + param_env: ty::ParamEnv<'tcx>, + original_values: &[ty::GenericArg<'tcx>], + var_values: CanonicalVarValues<'tcx>, + ) -> Result<(), NoSolution> { + assert_eq!(original_values.len(), var_values.len()); + for (&orig, response) in iter::zip(original_values, var_values.var_values) { + // This can fail due to the occurs check, see + // `tests/ui/typeck/lazy-norm/equating-projection-cyclically.rs` for an example + // where that can happen. + // + // FIXME: To deal with #105787 I also expect us to emit nested obligations here at + // some point. We can figure out how to deal with this once we actually have + // an ICE. + let nested_goals = self.eq(param_env, orig, response)?; + assert!(nested_goals.is_empty(), "{nested_goals:?}"); + } + + Ok(()) + } + + fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) { + for &(ty::OutlivesPredicate(lhs, rhs), _) in ®ion_constraints.outlives { + match lhs.unpack() { + GenericArgKind::Lifetime(lhs) => self.infcx.region_outlives_predicate( + &ObligationCause::dummy(), + ty::Binder::dummy(ty::OutlivesPredicate(lhs, rhs)), + ), + GenericArgKind::Type(lhs) => self.infcx.register_region_obligation_with_cause( + lhs, + rhs, + &ObligationCause::dummy(), + ), + GenericArgKind::Const(_) => bug!("const outlives: {lhs:?}: {rhs:?}"), + } + } + + for member_constraint in ®ion_constraints.member_constraints { + // FIXME: Deal with member constraints :< + let _ = member_constraint; + } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index c8097e81953..95612674eb9 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -19,8 +19,17 @@ use super::Goal; pub struct EvalCtxt<'a, 'tcx> { // FIXME: should be private. pub(super) infcx: &'a InferCtxt<'tcx>, - pub(super) var_values: CanonicalVarValues<'tcx>, + /// The highest universe index nameable by the caller. + /// + /// When we enter a new binder inside of the query we create new universes + /// which the caller cannot name. We have to be careful with variables from + /// these new universes when creating the query response. + /// + /// Both because these new universes can prevent us from reaching a fixpoint + /// if we have a coinductive cycle and because that's the only way we can return + /// new placeholders to the caller. + pub(super) max_input_universe: ty::UniverseIndex, pub(super) search_graph: &'a mut SearchGraph<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 71f536dd3cb..57b6a452737 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -19,11 +19,9 @@ use std::mem; use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; -use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse}; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::Obligation; -use rustc_middle::infer::canonical::Certainty as OldCertainty; use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ @@ -35,6 +33,7 @@ use crate::solve::search_graph::OverflowHandler; use crate::traits::ObligationCause; mod assembly; +mod canonical; mod eval_ctxt; mod fulfill; mod project_goals; @@ -89,11 +88,8 @@ trait CanonicalResponseExt { impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> { fn has_no_inference_or_external_constraints(&self) -> bool { - // so that we get a compile error when regions are supported - // so this code can be checked for being correct - let _: () = self.value.external_constraints.regions; - - self.value.var_values.is_identity() + self.value.external_constraints.region_constraints.is_empty() + && self.value.var_values.is_identity() && self.value.external_constraints.opaque_types.is_empty() } } @@ -169,6 +165,8 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { let result = EvalCtxt { search_graph: &mut search_graph, infcx: self, + // Only relevant when canonicalizing the response. + max_input_universe: ty::UniverseIndex::ROOT, var_values: CanonicalVarValues::dummy(), in_projection_eq_hack: false, } @@ -201,36 +199,33 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { search_graph.with_new_goal(tcx, canonical_goal, |search_graph| { let (ref infcx, goal, var_values) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal); - let mut ecx = - EvalCtxt { infcx, var_values, search_graph, in_projection_eq_hack: false }; + let mut ecx = EvalCtxt { + infcx, + var_values, + max_input_universe: canonical_goal.max_universe, + search_graph, + in_projection_eq_hack: false, + }; ecx.compute_goal(goal) }) } - fn make_canonical_response(&self, certainty: Certainty) -> QueryResult<'tcx> { - let external_constraints = compute_external_query_constraints(self.infcx)?; - - Ok(self.infcx.canonicalize_response(Response { - var_values: self.var_values, - external_constraints, - certainty, - })) - } - /// Recursively evaluates `goal`, returning whether any inference vars have /// been constrained and the certainty of the result. fn evaluate_goal( &mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>, ) -> Result<(bool, Certainty), NoSolution> { - let mut orig_values = OriginalQueryValues::default(); - let canonical_goal = self.infcx.canonicalize_query(goal, &mut orig_values); + let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let canonical_response = EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; let has_changed = !canonical_response.value.var_values.is_identity(); - let certainty = - instantiate_canonical_query_response(self.infcx, &orig_values, canonical_response); + let certainty = self.instantiate_and_apply_query_response( + goal.param_env, + orig_values, + canonical_response, + )?; // Check that rerunning this query with its inference constraints applied // doesn't result in new inference constraints and has the same result. @@ -244,8 +239,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { && !self.in_projection_eq_hack && !self.search_graph.in_cycle() { - let mut orig_values = OriginalQueryValues::default(); - let canonical_goal = self.infcx.canonicalize_query(goal, &mut orig_values); + let (_orig_values, canonical_goal) = self.canonicalize_goal(goal); let canonical_response = EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; if !canonical_response.value.var_values.is_identity() { @@ -316,15 +310,21 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { fn compute_type_outlives_goal( &mut self, - _goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>, + goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>, ) -> QueryResult<'tcx> { + let ty::OutlivesPredicate(ty, lt) = goal.predicate; + self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy()); self.make_canonical_response(Certainty::Yes) } fn compute_region_outlives_goal( &mut self, - _goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>, + goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>, ) -> QueryResult<'tcx> { + self.infcx.region_outlives_predicate( + &ObligationCause::dummy(), + ty::Binder::dummy(goal.predicate), + ); self.make_canonical_response(Certainty::Yes) } @@ -561,49 +561,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } -#[instrument(level = "debug", skip(infcx), ret)] -fn compute_external_query_constraints<'tcx>( - infcx: &InferCtxt<'tcx>, -) -> Result, NoSolution> { - let region_obligations = infcx.take_registered_region_obligations(); - let opaque_types = infcx.take_opaque_types_for_query_response(); - Ok(infcx.tcx.mk_external_constraints(ExternalConstraintsData { - // FIXME: Now that's definitely wrong :) - // - // Should also do the leak check here I think - regions: drop(region_obligations), - opaque_types, - })) -} - -fn instantiate_canonical_query_response<'tcx>( - infcx: &InferCtxt<'tcx>, - original_values: &OriginalQueryValues<'tcx>, - response: CanonicalResponse<'tcx>, -) -> Certainty { - let Ok(InferOk { value, obligations }) = infcx - .instantiate_query_response_and_region_obligations( - &ObligationCause::dummy(), - ty::ParamEnv::empty(), - original_values, - &response.unchecked_map(|resp| QueryResponse { - var_values: resp.var_values, - region_constraints: QueryRegionConstraints::default(), - certainty: match resp.certainty { - Certainty::Yes => OldCertainty::Proven, - Certainty::Maybe(_) => OldCertainty::Ambiguous, - }, - // FIXME: This to_owned makes me sad, but we should eventually impl - // `instantiate_query_response_and_region_obligations` separately - // instead of piggybacking off of the old implementation. - opaque_types: resp.external_constraints.opaque_types.to_owned(), - value: resp.certainty, - }), - ) else { bug!(); }; - assert!(obligations.is_empty()); - value -} - pub(super) fn response_no_constraints<'tcx>( tcx: TyCtxt<'tcx>, goal: Canonical<'tcx, impl Sized>, diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 88fd8bb8bd0..33c66d072e9 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -77,10 +77,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let nested_goals = self .eq(goal.param_env, goal.predicate.term, normalized_alias.into()) .expect("failed to unify with unconstrained term"); - let rhs_certainty = + + let unify_certainty = self.evaluate_all(nested_goals).expect("failed to unify with unconstrained term"); - self.make_canonical_response(normalization_certainty.unify_and(rhs_certainty)) + self.make_canonical_response(normalization_certainty.unify_and(unify_certainty)) } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 013db2edb39..870ecc2a970 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1175,7 +1175,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( /// paths you want to take. To make things worse, it was possible for /// cycles to arise, where you basically had a setup like ` /// as Trait>::Foo == $0`. Here, normalizing ` as -/// Trait>::Foo> to `[type error]` would lead to an obligation of +/// Trait>::Foo>` to `[type error]` would lead to an obligation of /// ` as Trait>::Foo`. We are supposed to report /// an error for this obligation, but we legitimately should not, /// because it contains `[type error]`. Yuck! (See issue #29857 for 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 4ad13dcb645..e91057356a2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -339,7 +339,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Essentially any user-written impl will match with an error type, // so creating `ImplCandidates` isn't useful. However, we might - // end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized) + // end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized`) // This helps us avoid overflow: see issue #72839 // Since compilation is already guaranteed to fail, this is just // to try to show the 'nicest' possible errors to the user. diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 01c1ad3a4ce..4377de15829 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -151,7 +151,7 @@ struct TraitObligationStack<'prev, 'tcx> { /// you don't want to cache that `B: AutoTrait` or `A: AutoTrait` /// is `EvaluatedToOk`; this is because they were only considered /// ok on the premise that if `A: AutoTrait` held, but we indeed - /// encountered a problem (later on) with `A: AutoTrait. So we + /// encountered a problem (later on) with `A: AutoTrait`. So we /// currently set a flag on the stack node for `B: AutoTrait` (as /// well as the second instance of `A: AutoTrait`) to suppress /// caching. @@ -727,7 +727,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Otherwise, we can say that `T: NonAutoTrait` is // true. // Let's imagine we have a predicate stack like - // `Foo: Bar -> WF(T) -> T: NonAutoTrait -> T: Auto + // `Foo: Bar -> WF(T) -> T: NonAutoTrait -> T: Auto` // depth ^1 ^2 ^3 // and the current predicate is `WF(T)`. `wf_args` // would contain `(T, 1)`. We want to check all diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index 33f2b5c1de9..995dd2f04b1 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -306,7 +306,7 @@ The maximum number of lines a function or method can have ### array-size-threshold The maximum allowed size for arrays on the stack -**Default Value:** `512000` (`u128`) +**Default Value:** `512000` (`u64`) * [large_stack_arrays](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays) * [large_const_arrays](https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays) diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 145cf524652..c626e0bd998 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -777,7 +777,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall)); store.register_late_pass(|_| Box::new(exit::Exit)); store.register_late_pass(|_| Box::new(to_digit_is_some::ToDigitIsSome)); - let array_size_threshold = conf.array_size_threshold; + let array_size_threshold = u128::from(conf.array_size_threshold); store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold))); store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold))); store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic)); diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index 5f74de5a288..1c7f3e96db8 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -334,7 +334,7 @@ define_Conf! { /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS. /// /// The maximum allowed size for arrays on the stack - (array_size_threshold: u128 = 512_000), + (array_size_threshold: u64 = 512_000), /// Lint: VEC_BOX. /// /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed diff --git a/src/tools/clippy/tests/ui/crashes/ice-10044.rs b/src/tools/clippy/tests/ui/crashes/ice-10044.rs deleted file mode 100644 index 65f38fe7118..00000000000 --- a/src/tools/clippy/tests/ui/crashes/ice-10044.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - [0; usize::MAX]; -} diff --git a/src/tools/clippy/tests/ui/crashes/ice-10044.stderr b/src/tools/clippy/tests/ui/crashes/ice-10044.stderr deleted file mode 100644 index 731f8265ad6..00000000000 --- a/src/tools/clippy/tests/ui/crashes/ice-10044.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: statement with no effect - --> $DIR/ice-10044.rs:2:5 - | -LL | [0; usize::MAX]; - | ^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::no-effect` implied by `-D warnings` - -error: aborting due to previous error - diff --git a/src/tools/clippy/tests/ui/large_stack_arrays.rs b/src/tools/clippy/tests/ui/large_stack_arrays.rs index 6790765f803..99787ffd3d3 100644 --- a/src/tools/clippy/tests/ui/large_stack_arrays.rs +++ b/src/tools/clippy/tests/ui/large_stack_arrays.rs @@ -24,6 +24,7 @@ fn main() { [S { data: [0; 32] }; 5000], [Some(""); 20_000_000], [E::T(0); 5000], + [0u8; usize::MAX], ); let good = ( diff --git a/src/tools/clippy/tests/ui/large_stack_arrays.stderr b/src/tools/clippy/tests/ui/large_stack_arrays.stderr index c7bf941ad00..24e90094982 100644 --- a/src/tools/clippy/tests/ui/large_stack_arrays.stderr +++ b/src/tools/clippy/tests/ui/large_stack_arrays.stderr @@ -31,5 +31,13 @@ LL | [E::T(0); 5000], | = help: consider allocating on the heap with `vec![E::T(0); 5000].into_boxed_slice()` -error: aborting due to 4 previous errors +error: allocating a local array larger than 512000 bytes + --> $DIR/large_stack_arrays.rs:27:9 + | +LL | [0u8; usize::MAX], + | ^^^^^^^^^^^^^^^^^ + | + = help: consider allocating on the heap with `vec![0u8; usize::MAX].into_boxed_slice()` + +error: aborting due to 5 previous errors diff --git a/tests/ui-toml/array_size_threshold/array_size_threshold.rs b/tests/ui-toml/array_size_threshold/array_size_threshold.rs new file mode 100644 index 00000000000..7f623c7a9ec --- /dev/null +++ b/tests/ui-toml/array_size_threshold/array_size_threshold.rs @@ -0,0 +1,10 @@ +#![allow(unused)] +#![warn(clippy::large_const_arrays, clippy::large_stack_arrays)] + +const ABOVE: [u8; 11] = [0; 11]; +const BELOW: [u8; 10] = [0; 10]; + +fn main() { + let above = [0u8; 11]; + let below = [0u8; 10]; +} diff --git a/tests/ui-toml/array_size_threshold/array_size_threshold.stderr b/tests/ui-toml/array_size_threshold/array_size_threshold.stderr new file mode 100644 index 00000000000..ac017b20916 --- /dev/null +++ b/tests/ui-toml/array_size_threshold/array_size_threshold.stderr @@ -0,0 +1,29 @@ +error: large array defined as const + --> $DIR/array_size_threshold.rs:4:1 + | +LL | const ABOVE: [u8; 11] = [0; 11]; + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: make this a static item: `static` + | + = note: `-D clippy::large-const-arrays` implied by `-D warnings` + +error: allocating a local array larger than 10 bytes + --> $DIR/array_size_threshold.rs:4:25 + | +LL | const ABOVE: [u8; 11] = [0; 11]; + | ^^^^^^^ + | + = help: consider allocating on the heap with `vec![0; 11].into_boxed_slice()` + = note: `-D clippy::large-stack-arrays` implied by `-D warnings` + +error: allocating a local array larger than 10 bytes + --> $DIR/array_size_threshold.rs:8:17 + | +LL | let above = [0u8; 11]; + | ^^^^^^^^^ + | + = help: consider allocating on the heap with `vec![0u8; 11].into_boxed_slice()` + +error: aborting due to 3 previous errors + diff --git a/tests/ui-toml/array_size_threshold/clippy.toml b/tests/ui-toml/array_size_threshold/clippy.toml new file mode 100644 index 00000000000..3f1fe9a1209 --- /dev/null +++ b/tests/ui-toml/array_size_threshold/clippy.toml @@ -0,0 +1 @@ +array-size-threshold = 10 diff --git a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr index 679ebd61ead..da72c8ebf19 100644 --- a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr +++ b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr @@ -17,7 +17,7 @@ note: the used `impl` has a `'static` requirement LL | impl MyTrait for dyn ObjectTrait { | ^^^^^^^^^^^^^^ this has an implicit `'static` lifetime requirement LL | fn use_self(&self) -> &() { panic!() } - | -------- calling this method introduces the `impl`'s 'static` requirement + | -------- calling this method introduces the `impl`'s `'static` requirement help: consider relaxing the implicit `'static` requirement | LL | impl MyTrait for dyn ObjectTrait + '_ { @@ -42,7 +42,7 @@ note: the used `impl` has a `'static` requirement LL | impl dyn ObjectTrait { | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement LL | fn use_self(&self) -> &() { panic!() } - | -------- calling this method introduces the `impl`'s 'static` requirement + | -------- calling this method introduces the `impl`'s `'static` requirement help: consider relaxing the implicit `'static` requirement | LL | impl dyn ObjectTrait + '_ { @@ -65,7 +65,7 @@ note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:87:26 | LL | fn use_self(&self) -> &() { panic!() } - | -------- calling this method introduces the `impl`'s 'static` requirement + | -------- calling this method introduces the `impl`'s `'static` requirement ... LL | impl MyTrait for dyn ObjectTrait {} | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement @@ -91,7 +91,7 @@ note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:106:26 | LL | fn use_self(&self) -> &() { panic!() } - | -------- calling this method introduces the `impl`'s 'static` requirement + | -------- calling this method introduces the `impl`'s `'static` requirement ... LL | impl MyTrait for dyn ObjectTrait {} | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement diff --git a/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs new file mode 100644 index 00000000000..3903bfe9bcf --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs @@ -0,0 +1,11 @@ +#![feature(non_lifetime_binders, generic_const_exprs)] +//~^ WARN the feature `non_lifetime_binders` is incomplete +//~| WARN the feature `generic_const_exprs` is incomplete + +fn foo() -> usize +where + for [i32; { let _: T = todo!(); 0 }]:, + //~^ ERROR cannot capture late-bound type parameter in a constant +{} + +fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.stderr b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.stderr new file mode 100644 index 00000000000..fafff02dea6 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.stderr @@ -0,0 +1,27 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/late-bound-in-anon-ct.rs:1:12 + | +LL | #![feature(non_lifetime_binders, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/late-bound-in-anon-ct.rs:1:34 + | +LL | #![feature(non_lifetime_binders, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 for more information + +error: cannot capture late-bound type parameter in a constant + --> $DIR/late-bound-in-anon-ct.rs:7:27 + | +LL | for [i32; { let _: T = todo!(); 0 }]:, + | - ^ + | | + | parameter defined here + +error: aborting due to previous error; 2 warnings emitted + diff --git a/tests/ui/typeck/bad-type-in-vec-contains.rs b/tests/ui/typeck/bad-type-in-vec-contains.rs new file mode 100644 index 00000000000..4433047b75a --- /dev/null +++ b/tests/ui/typeck/bad-type-in-vec-contains.rs @@ -0,0 +1,7 @@ +// The error message here still is pretty confusing. + +fn main() { + let primes = Vec::new(); + primes.contains(3); + //~^ ERROR mismatched types +} diff --git a/tests/ui/typeck/bad-type-in-vec-contains.stderr b/tests/ui/typeck/bad-type-in-vec-contains.stderr new file mode 100644 index 00000000000..0e03388d2d5 --- /dev/null +++ b/tests/ui/typeck/bad-type-in-vec-contains.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/bad-type-in-vec-contains.rs:5:21 + | +LL | primes.contains(3); + | -------- ^ + | | | + | | expected `&_`, found integer + | | help: consider borrowing here: `&3` + | arguments to this method are incorrect + | here the type of `primes` is inferred to be `[_]` + | + = note: expected reference `&_` + found type `{integer}` +note: method defined here + --> $SRC_DIR/core/src/slice/mod.rs:LL:COL + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`.