diff --git a/Cargo.lock b/Cargo.lock index 2e10b4c49abc..14ee031ad047 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4520,7 +4520,16 @@ dependencies = [ name = "rustc_next_trait_solver" version = "0.0.0" dependencies = [ + "bitflags 2.5.0", + "derivative", + "rustc_ast_ir", + "rustc_data_structures", + "rustc_index", + "rustc_macros", + "rustc_serialize", "rustc_type_ir", + "rustc_type_ir_macros", + "tracing", ] [[package]] diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 9cb193b4a678..fe888d2004f8 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -307,6 +307,8 @@ impl TraitBoundModifiers { pub enum GenericBound { Trait(PolyTraitRef, TraitBoundModifiers), Outlives(Lifetime), + /// Precise capturing syntax: `impl Sized + use<'a>` + Use(ThinVec, Span), } impl GenericBound { @@ -314,6 +316,7 @@ impl GenericBound { match self { GenericBound::Trait(t, ..) => t.span, GenericBound::Outlives(l) => l.ident.span, + GenericBound::Use(_, span) => *span, } } } @@ -2162,7 +2165,7 @@ pub enum TyKind { /// The `NodeId` exists to prevent lowering from having to /// generate `NodeId`s on the fly, which would complicate /// the generation of opaque `type Foo = impl Trait` items significantly. - ImplTrait(NodeId, GenericBounds, Option, Span)>>), + ImplTrait(NodeId, GenericBounds), /// No-op; kept solely so that we can pretty-print faithfully. Paren(P), /// Unused for now. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index cc33ce2cb562..182ad7359af8 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -523,14 +523,9 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { TyKind::TraitObject(bounds, _syntax) => { visit_vec(bounds, |bound| vis.visit_param_bound(bound)) } - TyKind::ImplTrait(id, bounds, precise_capturing) => { + TyKind::ImplTrait(id, bounds) => { vis.visit_id(id); visit_vec(bounds, |bound| vis.visit_param_bound(bound)); - if let Some((precise_capturing, _span)) = precise_capturing.as_deref_mut() { - for arg in precise_capturing { - vis.visit_precise_capturing_arg(arg); - } - } } TyKind::MacCall(mac) => vis.visit_mac_call(mac), TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => { @@ -923,6 +918,11 @@ fn noop_visit_param_bound(pb: &mut GenericBound, vis: &mut T) { match pb { GenericBound::Trait(ty, _modifier) => vis.visit_poly_trait_ref(ty), GenericBound::Outlives(lifetime) => noop_visit_lifetime(lifetime, vis), + GenericBound::Use(args, _) => { + for arg in args { + vis.visit_precise_capturing_arg(arg); + } + } } } diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 382c903625fb..4b2544ac47ed 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -184,7 +184,7 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> { None => break None, }, - ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds, _) => { + ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds) => { match bounds.last() { Some(ast::GenericBound::Trait(bound, _)) => { match path_return_type(&bound.trait_ref.path) { @@ -192,7 +192,9 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> { None => break None, } } - Some(ast::GenericBound::Outlives(_)) | None => break None, + Some(ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..)) | None => { + break None; + } } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index fa97c8db3267..104a401cd531 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -52,6 +52,16 @@ pub enum BoundKind { /// E.g., `trait A: B` SuperTraits, } +impl BoundKind { + pub fn descr(self) -> &'static str { + match self { + BoundKind::Bound => "bounds", + BoundKind::Impl => "`impl Trait`", + BoundKind::TraitObject => "`dyn` trait object bounds", + BoundKind::SuperTraits => "supertrait bounds", + } + } +} #[derive(Copy, Clone, Debug)] pub enum FnKind<'a> { @@ -497,13 +507,8 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { TyKind::TraitObject(bounds, ..) => { walk_list!(visitor, visit_param_bound, bounds, BoundKind::TraitObject); } - TyKind::ImplTrait(_, bounds, precise_capturing) => { + TyKind::ImplTrait(_, bounds) => { walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl); - if let Some((precise_capturing, _span)) = precise_capturing.as_deref() { - for arg in precise_capturing { - try_visit!(visitor.visit_precise_capturing_arg(arg)); - } - } } TyKind::Typeof(expression) => try_visit!(visitor.visit_anon_const(expression)), TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {} @@ -688,6 +693,10 @@ pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericB match bound { GenericBound::Trait(typ, _modifier) => visitor.visit_poly_trait_ref(typ), GenericBound::Outlives(lifetime) => visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound), + GenericBound::Use(args, _) => { + walk_list!(visitor, visit_precise_capturing_arg, args); + V::Result::output() + } } } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 10efe6fba655..7d81e45d314d 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -128,7 +128,7 @@ ast_lowering_never_pattern_with_guard = a guard on a never pattern will never be run .suggestion = remove this guard -ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed on argument-position `impl Trait` +ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed in argument-position `impl Trait` ast_lowering_previously_used_here = previously used here diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 88f6e6c3b780..da8682d3d095 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -50,10 +50,10 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; -use rustc_errors::{DiagArgFromDisplay, DiagCtxt, StashKey}; -use rustc_hir as hir; +use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::{self as hir}; use rustc_hir::{ ConstArg, GenericArg, HirId, ItemLocalMap, MissingLifetimeKind, ParamName, TraitCandidate, }; @@ -188,7 +188,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - pub(crate) fn dcx(&self) -> &'hir DiagCtxt { + pub(crate) fn dcx(&self) -> DiagCtxtHandle<'hir> { self.tcx.dcx() } } @@ -1384,6 +1384,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } None } + // Ignore `use` syntax since that is not valid in objects. + GenericBound::Use(_, span) => { + this.dcx() + .span_delayed_bug(*span, "use<> not allowed in dyn types"); + None + } })); let lifetime_bound = lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span)); @@ -1391,7 +1397,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }); hir::TyKind::TraitObject(bounds, lifetime_bound, *kind) } - TyKind::ImplTrait(def_node_id, bounds, precise_capturing) => { + TyKind::ImplTrait(def_node_id, bounds) => { let span = t.span; match itctx { ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait( @@ -1401,12 +1407,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bounds, fn_kind, itctx, - precise_capturing.as_deref().map(|(args, span)| (args.as_slice(), *span)), ), ImplTraitContext::Universal => { - if let Some(&(_, span)) = precise_capturing.as_deref() { + if let Some(span) = bounds.iter().find_map(|bound| match *bound { + ast::GenericBound::Use(_, span) => Some(span), + _ => None, + }) { self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnApit { span }); - }; + } + let span = t.span; // HACK: pprust breaks strings with newlines when the type @@ -1517,7 +1526,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bounds: &GenericBounds, fn_kind: Option, itctx: ImplTraitContext, - precise_capturing_args: Option<(&[PreciseCapturingArg], Span)>, ) -> hir::TyKind<'hir> { // Make sure we know that some funky desugaring has been going on here. // This is a first: there is code in other places like for loop @@ -1526,59 +1534,64 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // frequently opened issues show. let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); - let captured_lifetimes_to_duplicate = - if let Some((precise_capturing, _)) = precise_capturing_args { - // We'll actually validate these later on; all we need is the list of - // lifetimes to duplicate during this portion of lowering. - precise_capturing - .iter() - .filter_map(|arg| match arg { - PreciseCapturingArg::Lifetime(lt) => Some(*lt), - PreciseCapturingArg::Arg(..) => None, - }) - // Add in all the lifetimes mentioned in the bounds. We will error - // them out later, but capturing them here is important to make sure - // they actually get resolved in resolve_bound_vars. - .chain(lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)) - .collect() - } else { - match origin { - hir::OpaqueTyOrigin::TyAlias { .. } => { - // type alias impl trait and associated type position impl trait were - // decided to capture all in-scope lifetimes, which we collect for - // all opaques during resolution. + let captured_lifetimes_to_duplicate = if let Some(args) = + // We only look for one `use<...>` syntax since we syntactially reject more than one. + bounds.iter().find_map( + |bound| match bound { + ast::GenericBound::Use(a, _) => Some(a), + _ => None, + }, + ) { + // We'll actually validate these later on; all we need is the list of + // lifetimes to duplicate during this portion of lowering. + args.iter() + .filter_map(|arg| match arg { + PreciseCapturingArg::Lifetime(lt) => Some(*lt), + PreciseCapturingArg::Arg(..) => None, + }) + // Add in all the lifetimes mentioned in the bounds. We will error + // them out later, but capturing them here is important to make sure + // they actually get resolved in resolve_bound_vars. + .chain(lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)) + .collect() + } else { + match origin { + hir::OpaqueTyOrigin::TyAlias { .. } => { + // type alias impl trait and associated type position impl trait were + // decided to capture all in-scope lifetimes, which we collect for + // all opaques during resolution. + self.resolver + .take_extra_lifetime_params(opaque_ty_node_id) + .into_iter() + .map(|(ident, id, _)| Lifetime { id, ident }) + .collect() + } + hir::OpaqueTyOrigin::FnReturn(..) => { + if matches!( + fn_kind.expect("expected RPITs to be lowered with a FnKind"), + FnDeclKind::Impl | FnDeclKind::Trait + ) || self.tcx.features().lifetime_capture_rules_2024 + || span.at_least_rust_2024() + { + // return-position impl trait in trait was decided to capture all + // in-scope lifetimes, which we collect for all opaques during resolution. self.resolver .take_extra_lifetime_params(opaque_ty_node_id) .into_iter() .map(|(ident, id, _)| Lifetime { id, ident }) .collect() - } - hir::OpaqueTyOrigin::FnReturn(..) => { - if matches!( - fn_kind.expect("expected RPITs to be lowered with a FnKind"), - FnDeclKind::Impl | FnDeclKind::Trait - ) || self.tcx.features().lifetime_capture_rules_2024 - || span.at_least_rust_2024() - { - // return-position impl trait in trait was decided to capture all - // in-scope lifetimes, which we collect for all opaques during resolution. - self.resolver - .take_extra_lifetime_params(opaque_ty_node_id) - .into_iter() - .map(|(ident, id, _)| Lifetime { id, ident }) - .collect() - } else { - // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` - // example, we only need to duplicate lifetimes that appear in the - // bounds, since those are the only ones that are captured by the opaque. - lifetime_collector::lifetimes_in_bounds(self.resolver, bounds) - } - } - hir::OpaqueTyOrigin::AsyncFn(..) => { - unreachable!("should be using `lower_async_fn_ret_ty`") + } else { + // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` + // example, we only need to duplicate lifetimes that appear in the + // bounds, since those are the only ones that are captured by the opaque. + lifetime_collector::lifetimes_in_bounds(self.resolver, bounds) } } - }; + hir::OpaqueTyOrigin::AsyncFn(..) => { + unreachable!("should be using `lower_async_fn_ret_ty`") + } + } + }; debug!(?captured_lifetimes_to_duplicate); self.lower_opaque_inner( @@ -1588,7 +1601,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { captured_lifetimes_to_duplicate, span, opaque_ty_span, - precise_capturing_args, |this| this.lower_param_bounds(bounds, itctx), ) } @@ -1601,7 +1613,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { captured_lifetimes_to_duplicate: FxIndexSet, span: Span, opaque_ty_span: Span, - precise_capturing_args: Option<(&[PreciseCapturingArg], Span)>, lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>], ) -> hir::TyKind<'hir> { let opaque_ty_def_id = self.create_def( @@ -1688,18 +1699,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Install the remapping from old to new (if any). This makes sure that // any lifetimes that would have resolved to the def-id of captured // lifetimes are remapped to the new *synthetic* lifetimes of the opaque. - let (bounds, precise_capturing_args) = - this.with_remapping(captured_to_synthesized_mapping, |this| { - ( - lower_item_bounds(this), - precise_capturing_args.map(|(precise_capturing, span)| { - ( - this.lower_precise_capturing_args(precise_capturing), - this.lower_span(span), - ) - }), - ) - }); + let bounds = this + .with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this)); let generic_params = this.arena.alloc_from_iter(synthesized_lifetime_definitions.iter().map( @@ -1744,7 +1745,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { origin, lifetime_mapping, in_trait, - precise_capturing_args, }; // Generate an `type Foo = impl Trait;` declaration. @@ -1955,7 +1955,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { captured_lifetimes, span, opaque_ty_span, - None, |this| { let bound = this.lower_coroutine_fn_output_type_to_bound( output, @@ -2038,6 +2037,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { GenericBound::Outlives(lifetime) => { hir::GenericBound::Outlives(self.lower_lifetime(lifetime)) } + GenericBound::Use(args, span) => hir::GenericBound::Use( + self.lower_precise_capturing_args(args), + self.lower_span(*span), + ), } } diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 9a8689e27c06..2626631d8004 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -215,6 +215,11 @@ ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer t ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations .label = pattern not allowed in foreign function +ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing syntax + .label = second `use<...>` here + +ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc} + ast_passes_show_span = {$msg} ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 0fbb288cc968..b274a9b9114a 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -12,6 +12,7 @@ use rustc_ast::visit::{walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor} use rustc_ast::*; use rustc_ast_pretty::pprust::{self, State}; use rustc_data_structures::fx::FxIndexMap; +use rustc_errors::DiagCtxtHandle; use rustc_feature::Features; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{ @@ -193,8 +194,24 @@ impl<'a> AstValidator<'a> { // Mirrors `visit::walk_ty`, but tracks relevant state. fn walk_ty(&mut self, t: &'a Ty) { match &t.kind { - TyKind::ImplTrait(..) => { - self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)) + TyKind::ImplTrait(_, bounds) => { + self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)); + + // FIXME(precise_capturing): If we were to allow `use` in other positions + // (e.g. GATs), then we must validate those as well. However, we don't have + // a good way of doing this with the current `Visitor` structure. + let mut use_bounds = bounds + .iter() + .filter_map(|bound| match bound { + GenericBound::Use(_, span) => Some(span), + _ => None, + }) + .copied(); + if let Some(bound1) = use_bounds.next() + && let Some(bound2) = use_bounds.next() + { + self.dcx().emit_err(errors::DuplicatePreciseCapturing { bound1, bound2 }); + } } TyKind::TraitObject(..) => self .with_tilde_const(Some(DisallowTildeConstContext::TraitObject), |this| { @@ -253,7 +270,7 @@ impl<'a> AstValidator<'a> { } } - fn dcx(&self) -> &rustc_errors::DiagCtxt { + fn dcx(&self) -> DiagCtxtHandle<'a> { self.session.dcx() } @@ -751,7 +768,7 @@ impl<'a> AstValidator<'a> { } } } - TyKind::ImplTrait(_, bounds, _) => { + TyKind::ImplTrait(_, bounds) => { if self.is_impl_trait_banned { self.dcx().emit_err(errors::ImplTraitPath { span: ty.span }); } @@ -793,11 +810,7 @@ impl<'a> AstValidator<'a> { /// Checks that generic parameters are in the correct order, /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`) -fn validate_generic_param_order( - dcx: &rustc_errors::DiagCtxt, - generics: &[GenericParam], - span: Span, -) { +fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericParam], span: Span) { let mut max_param: Option = None; let mut out_of_order = FxIndexMap::default(); let mut param_idents = Vec::with_capacity(generics.len()); @@ -1304,6 +1317,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } GenericBound::Outlives(_) => {} + GenericBound::Use(..) => {} } } } @@ -1322,95 +1336,110 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) { - if let GenericBound::Trait(poly, modifiers) = bound { - match (ctxt, modifiers.constness, modifiers.polarity) { - (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => { - self.dcx().emit_err(errors::OptionalTraitSupertrait { - span: poly.span, - path_str: pprust::path_to_string(&poly.trait_ref.path), - }); + match bound { + GenericBound::Trait(trait_ref, modifiers) => { + match (ctxt, modifiers.constness, modifiers.polarity) { + (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => { + self.dcx().emit_err(errors::OptionalTraitSupertrait { + span: trait_ref.span, + path_str: pprust::path_to_string(&trait_ref.trait_ref.path), + }); + } + (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => { + self.dcx().emit_err(errors::OptionalTraitObject { span: trait_ref.span }); + } + ( + BoundKind::TraitObject, + BoundConstness::Always(_), + BoundPolarity::Positive, + ) => { + self.dcx().emit_err(errors::ConstBoundTraitObject { span: trait_ref.span }); + } + (_, BoundConstness::Maybe(span), BoundPolarity::Positive) + if let Some(reason) = &self.disallow_tilde_const => + { + let reason = match reason { + DisallowTildeConstContext::Fn(FnKind::Closure(..)) => { + errors::TildeConstReason::Closure + } + DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => { + errors::TildeConstReason::Function { ident: ident.span } + } + &DisallowTildeConstContext::Trait(span) => { + errors::TildeConstReason::Trait { span } + } + &DisallowTildeConstContext::TraitImpl(span) => { + errors::TildeConstReason::TraitImpl { span } + } + &DisallowTildeConstContext::Impl(span) => { + // FIXME(effects): Consider providing a help message or even a structured + // suggestion for moving such bounds to the assoc const fns if available. + errors::TildeConstReason::Impl { span } + } + &DisallowTildeConstContext::TraitAssocTy(span) => { + errors::TildeConstReason::TraitAssocTy { span } + } + &DisallowTildeConstContext::TraitImplAssocTy(span) => { + errors::TildeConstReason::TraitImplAssocTy { span } + } + &DisallowTildeConstContext::InherentAssocTy(span) => { + errors::TildeConstReason::InherentAssocTy { span } + } + DisallowTildeConstContext::TraitObject => { + errors::TildeConstReason::TraitObject + } + DisallowTildeConstContext::Item => errors::TildeConstReason::Item, + }; + self.dcx().emit_err(errors::TildeConstDisallowed { span, reason }); + } + ( + _, + BoundConstness::Always(_) | BoundConstness::Maybe(_), + BoundPolarity::Negative(_) | BoundPolarity::Maybe(_), + ) => { + self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers { + span: bound.span(), + left: modifiers.constness.as_str(), + right: modifiers.polarity.as_str(), + }); + } + _ => {} } - (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => { - self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span }); - } - (BoundKind::TraitObject, BoundConstness::Always(_), BoundPolarity::Positive) => { - self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span }); - } - (_, BoundConstness::Maybe(span), BoundPolarity::Positive) - if let Some(reason) = &self.disallow_tilde_const => - { - let reason = match reason { - DisallowTildeConstContext::Fn(FnKind::Closure(..)) => { - errors::TildeConstReason::Closure - } - DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => { - errors::TildeConstReason::Function { ident: ident.span } - } - &DisallowTildeConstContext::Trait(span) => { - errors::TildeConstReason::Trait { span } - } - &DisallowTildeConstContext::TraitImpl(span) => { - errors::TildeConstReason::TraitImpl { span } - } - &DisallowTildeConstContext::Impl(span) => { - // FIXME(effects): Consider providing a help message or even a structured - // suggestion for moving such bounds to the assoc const fns if available. - errors::TildeConstReason::Impl { span } - } - &DisallowTildeConstContext::TraitAssocTy(span) => { - errors::TildeConstReason::TraitAssocTy { span } - } - &DisallowTildeConstContext::TraitImplAssocTy(span) => { - errors::TildeConstReason::TraitImplAssocTy { span } - } - &DisallowTildeConstContext::InherentAssocTy(span) => { - errors::TildeConstReason::InherentAssocTy { span } - } - DisallowTildeConstContext::TraitObject => { - errors::TildeConstReason::TraitObject - } - DisallowTildeConstContext::Item => errors::TildeConstReason::Item, - }; - self.dcx().emit_err(errors::TildeConstDisallowed { span, reason }); - } - ( - _, - BoundConstness::Always(_) | BoundConstness::Maybe(_), - BoundPolarity::Negative(_) | BoundPolarity::Maybe(_), - ) => { - self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers { - span: bound.span(), - left: modifiers.constness.as_str(), - right: modifiers.polarity.as_str(), - }); - } - _ => {} - } - } - // Negative trait bounds are not allowed to have associated constraints - if let GenericBound::Trait(trait_ref, modifiers) = bound - && let BoundPolarity::Negative(_) = modifiers.polarity - && let Some(segment) = trait_ref.trait_ref.path.segments.last() - { - match segment.args.as_deref() { - Some(ast::GenericArgs::AngleBracketed(args)) => { - for arg in &args.args { - if let ast::AngleBracketedArg::Constraint(constraint) = arg { - self.dcx().emit_err(errors::ConstraintOnNegativeBound { - span: constraint.span, + // Negative trait bounds are not allowed to have associated constraints + if let BoundPolarity::Negative(_) = modifiers.polarity + && let Some(segment) = trait_ref.trait_ref.path.segments.last() + { + match segment.args.as_deref() { + Some(ast::GenericArgs::AngleBracketed(args)) => { + for arg in &args.args { + if let ast::AngleBracketedArg::Constraint(constraint) = arg { + self.dcx().emit_err(errors::ConstraintOnNegativeBound { + span: constraint.span, + }); + } + } + } + // The lowered form of parenthesized generic args contains an associated type binding. + Some(ast::GenericArgs::Parenthesized(args)) => { + self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation { + span: args.span, }); } + None => {} } } - // The lowered form of parenthesized generic args contains an associated type binding. - Some(ast::GenericArgs::Parenthesized(args)) => { - self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation { - span: args.span, + } + GenericBound::Outlives(_) => {} + GenericBound::Use(_, span) => match ctxt { + BoundKind::Impl => {} + BoundKind::Bound | BoundKind::TraitObject | BoundKind::SuperTraits => { + self.dcx().emit_err(errors::PreciseCapturingNotAllowedHere { + loc: ctxt.descr(), + span: *span, }); } - None => {} - } + }, } visit::walk_param_bound(self, bound) diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 260c182bd9e4..601910ded208 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -844,3 +844,20 @@ pub struct MatchArmWithNoBody { #[suggestion(code = " => todo!(),", applicability = "has-placeholders")] pub suggestion: Span, } + +#[derive(Diagnostic)] +#[diag(ast_passes_precise_capturing_not_allowed_here)] +pub struct PreciseCapturingNotAllowedHere { + #[primary_span] + pub span: Span, + pub loc: &'static str, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_precise_capturing_duplicated)] +pub struct DuplicatePreciseCapturing { + #[primary_span] + pub bound1: Span, + #[label] + pub bound2: Span, +} diff --git a/compiler/rustc_ast_passes/src/show_span.rs b/compiler/rustc_ast_passes/src/show_span.rs index 105900742822..e7ba2e7fc30b 100644 --- a/compiler/rustc_ast_passes/src/show_span.rs +++ b/compiler/rustc_ast_passes/src/show_span.rs @@ -8,6 +8,7 @@ use std::str::FromStr; use rustc_ast as ast; use rustc_ast::visit; use rustc_ast::visit::Visitor; +use rustc_errors::DiagCtxtHandle; use crate::errors; @@ -31,7 +32,7 @@ impl FromStr for Mode { } struct ShowSpanVisitor<'a> { - dcx: &'a rustc_errors::DiagCtxt, + dcx: DiagCtxtHandle<'a>, mode: Mode, } @@ -58,7 +59,7 @@ impl<'a> Visitor<'a> for ShowSpanVisitor<'a> { } } -pub fn run(dcx: &rustc_errors::DiagCtxt, mode: &str, krate: &ast::Crate) { +pub fn run(dcx: DiagCtxtHandle<'_>, mode: &str, krate: &ast::Crate) { let Ok(mode) = mode.parse() else { return; }; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 4eb2a103fd8f..0225c95dca8e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1187,17 +1187,8 @@ impl<'a> State<'a> { } self.print_type_bounds(bounds); } - ast::TyKind::ImplTrait(_, bounds, precise_capturing_args) => { + ast::TyKind::ImplTrait(_, bounds) => { self.word_nbsp("impl"); - if let Some((precise_capturing_args, ..)) = precise_capturing_args.as_deref() { - self.word("use"); - self.word("<"); - self.commasep(Inconsistent, precise_capturing_args, |s, arg| match arg { - ast::PreciseCapturingArg::Arg(p, _) => s.print_path(p, false, 0), - ast::PreciseCapturingArg::Lifetime(lt) => s.print_lifetime(*lt), - }); - self.word(">") - } self.print_type_bounds(bounds); } ast::TyKind::Array(ty, length) => { @@ -1800,6 +1791,15 @@ impl<'a> State<'a> { self.print_poly_trait_ref(tref); } GenericBound::Outlives(lt) => self.print_lifetime(*lt), + GenericBound::Use(args, _) => { + self.word("use"); + self.word("<"); + self.commasep(Inconsistent, args, |s, arg| match arg { + ast::PreciseCapturingArg::Arg(p, _) => s.print_path(p, false, 0), + ast::PreciseCapturingArg::Lifetime(lt) => s.print_lifetime(*lt), + }); + self.word(">") + } } } } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 5113c5adc8f7..34c24a26f7b1 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -596,7 +596,7 @@ pub fn eval_condition( features: Option<&Features>, eval: &mut impl FnMut(Condition) -> bool, ) -> bool { - let dcx = &sess.psess.dcx; + let dcx = sess.dcx(); match &cfg.kind { ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => { try_gate_cfg(sym::version, cfg.span, sess, features); diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 303909de3435..0cffeed0a755 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -1,7 +1,8 @@ use std::num::IntErrorKind; use rustc_ast as ast; -use rustc_errors::{codes::*, Applicability, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level}; +use rustc_errors::DiagCtxtHandle; +use rustc_errors::{codes::*, Applicability, Diag, Diagnostic, EmissionGuarantee, Level}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -49,7 +50,7 @@ pub(crate) struct UnknownMetaItem<'a> { // Manual implementation to be able to format `expected` items correctly. impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnknownMetaItem<'_> { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::>(); Diag::new(dcx, level, fluent::attr_unknown_meta_item) .with_span(self.span) @@ -202,7 +203,7 @@ pub(crate) struct UnsupportedLiteral { } impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut diag = Diag::new( dcx, level, diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 622feb4e4c73..c1f753282725 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -1,13 +1,13 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -use rustc_errors::{codes::*, struct_span_code_err, Diag, DiagCtxt}; +use rustc_errors::{codes::*, struct_span_code_err, Diag, DiagCtxtHandle}; use rustc_middle::span_bug; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { - pub fn dcx(&self) -> &'tcx DiagCtxt { + pub fn dcx(&self) -> DiagCtxtHandle<'tcx> { self.infcx.dcx() } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 6bc340e44f5b..197da3eb6416 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -228,7 +228,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { seen_spans.insert(move_span); } - use_spans.var_path_only_subdiag(self.dcx(), &mut err, desired_action); + use_spans.var_path_only_subdiag(&mut err, desired_action); if !is_loop_move { err.span_label( @@ -303,24 +303,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if needs_note { if let Some(local) = place.as_local() { let span = self.body.local_decls[local].source_info.span; - err.subdiagnostic( - self.dcx(), - crate::session_diagnostics::TypeNoCopy::Label { - is_partial_move, - ty, - place: ¬e_msg, - span, - }, - ); + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { + is_partial_move, + ty, + place: ¬e_msg, + span, + }); } else { - err.subdiagnostic( - self.dcx(), - crate::session_diagnostics::TypeNoCopy::Note { - is_partial_move, - ty, - place: ¬e_msg, - }, - ); + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note { + is_partial_move, + ty, + place: ¬e_msg, + }); }; } @@ -597,7 +591,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { E0381, "{used} binding {desc}{isnt_initialized}" ); - use_spans.var_path_only_subdiag(self.dcx(), &mut err, desired_action); + use_spans.var_path_only_subdiag(&mut err, desired_action); if let InitializationRequiringAction::PartialAssignment | InitializationRequiringAction::Assignment = desired_action @@ -996,7 +990,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self, err: &mut Diag<'_>, ty: Ty<'tcx>, - expr: &'cx hir::Expr<'cx>, + expr: &hir::Expr<'_>, ) { let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); let hir::ExprKind::Struct(struct_qpath, fields, Some(base)) = expr.kind else { return }; @@ -1084,8 +1078,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self, err: &mut Diag<'_>, ty: Ty<'tcx>, - mut expr: &'cx hir::Expr<'cx>, - mut other_expr: Option<&'cx hir::Expr<'cx>>, + mut expr: &'tcx hir::Expr<'tcx>, + mut other_expr: Option<&'tcx hir::Expr<'tcx>>, use_spans: Option>, ) { if let hir::ExprKind::Struct(_, _, Some(_)) = expr.kind { @@ -1410,13 +1404,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &value_msg, ); - borrow_spans.var_path_only_subdiag( - self.dcx(), - &mut err, - crate::InitializationRequiringAction::Borrow, - ); + borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow); - move_spans.var_subdiag(self.dcx(), &mut err, None, |kind, var_span| { + move_spans.var_subdiag(&mut err, None, |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; match kind { hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span }, @@ -1468,7 +1458,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_span, &self.describe_any_place(borrow.borrowed_place.as_ref()), ); - borrow_spans.var_subdiag(self.dcx(), &mut err, Some(borrow.kind), |kind, var_span| { + borrow_spans.var_subdiag(&mut err, Some(borrow.kind), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; let place = &borrow.borrowed_place; let desc_place = self.describe_any_place(place.as_ref()); @@ -1633,7 +1623,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "mutably borrow", ); borrow_spans.var_subdiag( - self.dcx(), &mut err, Some(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }), |kind, var_span| { @@ -1730,64 +1719,45 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }; if issued_spans == borrow_spans { - borrow_spans.var_subdiag( - self.dcx(), - &mut err, - Some(gen_borrow_kind), - |kind, var_span| { - use crate::session_diagnostics::CaptureVarCause::*; - match kind { - hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine { - place: desc_place, - var_span, - is_single_var: false, - }, - hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - BorrowUsePlaceClosure { - place: desc_place, - var_span, - is_single_var: false, - } - } + borrow_spans.var_subdiag(&mut err, Some(gen_borrow_kind), |kind, var_span| { + use crate::session_diagnostics::CaptureVarCause::*; + match kind { + hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine { + place: desc_place, + var_span, + is_single_var: false, + }, + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { + BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false } } - }, - ); + } + }); } else { - issued_spans.var_subdiag( - self.dcx(), - &mut err, - Some(issued_borrow.kind), - |kind, var_span| { - use crate::session_diagnostics::CaptureVarCause::*; - let borrow_place = &issued_borrow.borrowed_place; - let borrow_place_desc = self.describe_any_place(borrow_place.as_ref()); - match kind { - hir::ClosureKind::Coroutine(_) => { - FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span } - } - hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span } - } + issued_spans.var_subdiag(&mut err, Some(issued_borrow.kind), |kind, var_span| { + use crate::session_diagnostics::CaptureVarCause::*; + let borrow_place = &issued_borrow.borrowed_place; + let borrow_place_desc = self.describe_any_place(borrow_place.as_ref()); + match kind { + hir::ClosureKind::Coroutine(_) => { + FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span } } - }, - ); + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { + FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span } + } + } + }); - borrow_spans.var_subdiag( - self.dcx(), - &mut err, - Some(gen_borrow_kind), - |kind, var_span| { - use crate::session_diagnostics::CaptureVarCause::*; - match kind { - hir::ClosureKind::Coroutine(_) => { - SecondBorrowUsePlaceCoroutine { place: desc_place, var_span } - } - hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - SecondBorrowUsePlaceClosure { place: desc_place, var_span } - } + borrow_spans.var_subdiag(&mut err, Some(gen_borrow_kind), |kind, var_span| { + use crate::session_diagnostics::CaptureVarCause::*; + match kind { + hir::ClosureKind::Coroutine(_) => { + SecondBorrowUsePlaceCoroutine { place: desc_place, var_span } } - }, - ); + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { + SecondBorrowUsePlaceClosure { place: desc_place, var_span } + } + } + }); } if union_type_name != "" { @@ -2016,7 +1986,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } - pub(crate) fn find_expr(&self, span: Span) -> Option<&hir::Expr<'_>> { + pub(crate) fn find_expr(&self, span: Span) -> Option<&'tcx hir::Expr<'tcx>> { let tcx = self.infcx.tcx; let body_id = tcx.hir_node(self.mir_hir_id()).body_id()?; let mut expr_finder = FindExprBySpan::new(span, tcx); @@ -2961,7 +2931,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label(borrow_span, "borrowed value does not live long enough"); err.span_label(drop_span, format!("`{name}` dropped here while still borrowed")); - borrow_spans.args_subdiag(self.dcx(), &mut err, |args_span| { + borrow_spans.args_subdiag(&mut err, |args_span| { crate::session_diagnostics::CaptureArgLabel::Capture { is_within: borrow_spans.for_coroutine(), args_span, @@ -3219,7 +3189,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None, ); - borrow_spans.args_subdiag(self.dcx(), &mut err, |args_span| { + borrow_spans.args_subdiag(&mut err, |args_span| { crate::session_diagnostics::CaptureArgLabel::Capture { is_within: borrow_spans.for_coroutine(), args_span, @@ -3680,7 +3650,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "assign", ); - loan_spans.var_subdiag(self.dcx(), &mut err, Some(loan.kind), |kind, var_span| { + loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; match kind { hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span }, @@ -3698,7 +3668,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place); - loan_spans.var_subdiag(self.dcx(), &mut err, Some(loan.kind), |kind, var_span| { + loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; match kind { hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span }, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index abb0b5afbd8b..5b4269caccb5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -4,8 +4,8 @@ use crate::session_diagnostics::{ CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause, CaptureVarKind, CaptureVarPathUseCause, OnClosureNote, }; +use rustc_errors::MultiSpan; use rustc_errors::{Applicability, Diag}; -use rustc_errors::{DiagCtxt, MultiSpan}; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::CoroutineKind; use rustc_hir::{self as hir, LangItem}; @@ -130,16 +130,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() { let did = did.expect_local(); if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { - diag.subdiagnostic( - self.dcx(), - OnClosureNote::InvokedTwice { - place_name: &ty::place_to_string_for_capture( - self.infcx.tcx, - hir_place, - ), - span: *span, - }, - ); + diag.subdiagnostic(OnClosureNote::InvokedTwice { + place_name: &ty::place_to_string_for_capture( + self.infcx.tcx, + hir_place, + ), + span: *span, + }); return true; } } @@ -152,13 +149,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() { let did = did.expect_local(); if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { - diag.subdiagnostic( - self.dcx(), - OnClosureNote::MovedTwice { - place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place), - span: *span, - }, - ); + diag.subdiagnostic(OnClosureNote::MovedTwice { + place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place), + span: *span, + }); return true; } } @@ -591,14 +585,9 @@ impl UseSpans<'_> { /// Add a span label to the arguments of the closure, if it exists. #[allow(rustc::diagnostic_outside_of_impl)] - pub(super) fn args_subdiag( - self, - dcx: &DiagCtxt, - err: &mut Diag<'_>, - f: impl FnOnce(Span) -> CaptureArgLabel, - ) { + pub(super) fn args_subdiag(self, err: &mut Diag<'_>, f: impl FnOnce(Span) -> CaptureArgLabel) { if let UseSpans::ClosureUse { args_span, .. } = self { - err.subdiagnostic(dcx, f(args_span)); + err.subdiagnostic(f(args_span)); } } @@ -607,7 +596,6 @@ impl UseSpans<'_> { #[allow(rustc::diagnostic_outside_of_impl)] pub(super) fn var_path_only_subdiag( self, - dcx: &DiagCtxt, err: &mut Diag<'_>, action: crate::InitializationRequiringAction, ) { @@ -616,26 +604,20 @@ impl UseSpans<'_> { if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self { match closure_kind { hir::ClosureKind::Coroutine(_) => { - err.subdiagnostic( - dcx, - match action { - Borrow => BorrowInCoroutine { path_span }, - MatchOn | Use => UseInCoroutine { path_span }, - Assignment => AssignInCoroutine { path_span }, - PartialAssignment => AssignPartInCoroutine { path_span }, - }, - ); + err.subdiagnostic(match action { + Borrow => BorrowInCoroutine { path_span }, + MatchOn | Use => UseInCoroutine { path_span }, + Assignment => AssignInCoroutine { path_span }, + PartialAssignment => AssignPartInCoroutine { path_span }, + }); } hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - err.subdiagnostic( - dcx, - match action { - Borrow => BorrowInClosure { path_span }, - MatchOn | Use => UseInClosure { path_span }, - Assignment => AssignInClosure { path_span }, - PartialAssignment => AssignPartInClosure { path_span }, - }, - ); + err.subdiagnostic(match action { + Borrow => BorrowInClosure { path_span }, + MatchOn | Use => UseInClosure { path_span }, + Assignment => AssignInClosure { path_span }, + PartialAssignment => AssignPartInClosure { path_span }, + }); } } } @@ -645,32 +627,28 @@ impl UseSpans<'_> { #[allow(rustc::diagnostic_outside_of_impl)] pub(super) fn var_subdiag( self, - dcx: &DiagCtxt, err: &mut Diag<'_>, kind: Option, f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause, ) { if let UseSpans::ClosureUse { closure_kind, capture_kind_span, path_span, .. } = self { if capture_kind_span != path_span { - err.subdiagnostic( - dcx, - match kind { - Some(kd) => match kd { - rustc_middle::mir::BorrowKind::Shared - | rustc_middle::mir::BorrowKind::Fake(_) => { - CaptureVarKind::Immut { kind_span: capture_kind_span } - } + err.subdiagnostic(match kind { + Some(kd) => match kd { + rustc_middle::mir::BorrowKind::Shared + | rustc_middle::mir::BorrowKind::Fake(_) => { + CaptureVarKind::Immut { kind_span: capture_kind_span } + } - rustc_middle::mir::BorrowKind::Mut { .. } => { - CaptureVarKind::Mut { kind_span: capture_kind_span } - } - }, - None => CaptureVarKind::Move { kind_span: capture_kind_span }, + rustc_middle::mir::BorrowKind::Mut { .. } => { + CaptureVarKind::Mut { kind_span: capture_kind_span } + } }, - ); + None => CaptureVarKind::Move { kind_span: capture_kind_span }, + }); }; let diag = f(closure_kind, path_span); - err.subdiagnostic(dcx, diag); + err.subdiagnostic(diag); } } @@ -1042,15 +1020,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { CallKind::FnCall { fn_trait_id, self_ty } if self.infcx.tcx.is_lang_item(fn_trait_id, LangItem::FnOnce) => { - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::Call { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }, - ); + err.subdiagnostic(CaptureReasonLabel::Call { + fn_call_span, + place_name: &place_name, + is_partial, + is_loop_message, + }); // Check if the move occurs on a value because of a call on a closure that comes // from a type parameter `F: FnOnce()`. If so, we provide a targeted `note`: // ``` @@ -1119,27 +1094,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); err.span_note(span, fluent::borrowck_moved_a_fn_once_in_call_call); } else { - err.subdiagnostic( - self.dcx(), - CaptureReasonNote::FnOnceMoveInCall { var_span }, - ); + err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span }); } } CallKind::Operator { self_arg, trait_id, .. } => { let self_arg = self_arg.unwrap(); - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::OperatorUse { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }, - ); + err.subdiagnostic(CaptureReasonLabel::OperatorUse { + fn_call_span, + place_name: &place_name, + is_partial, + is_loop_message, + }); if self.fn_self_span_reported.insert(fn_span) { let lang = self.infcx.tcx.lang_items(); err.subdiagnostic( - self.dcx(), if [lang.not_trait(), lang.deref_trait(), lang.neg_trait()] .contains(&Some(trait_id)) { @@ -1164,14 +1132,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); let func = tcx.def_path_str(method_did); - err.subdiagnostic( - self.dcx(), - CaptureReasonNote::FuncTakeSelf { - func, - place_name: place_name.clone(), - span: self_arg.span, - }, - ); + err.subdiagnostic(CaptureReasonNote::FuncTakeSelf { + func, + place_name: place_name.clone(), + span: self_arg.span, + }); } let parent_did = tcx.parent(method_did); let parent_self_ty = @@ -1185,10 +1150,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result)) }); if is_option_or_result && maybe_reinitialized_locations_is_empty { - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::BorrowContent { var_span }, - ); + err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span }); } if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring { let ty = moved_place.ty(self.body, tcx).ty; @@ -1202,24 +1164,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { _ => false, }; if suggest { - err.subdiagnostic( - self.dcx(), - CaptureReasonSuggest::IterateSlice { - ty, - span: move_span.shrink_to_lo(), - }, - ); + err.subdiagnostic(CaptureReasonSuggest::IterateSlice { + ty, + span: move_span.shrink_to_lo(), + }); } - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::ImplicitCall { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }, - ); + err.subdiagnostic(CaptureReasonLabel::ImplicitCall { + fn_call_span, + place_name: &place_name, + is_partial, + is_loop_message, + }); // If the moved place was a `&mut` ref, then we can // suggest to reborrow it where it was moved, so it // will still be valid by the time we get to the usage. @@ -1243,25 +1199,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } else { if let Some((CallDesugaringKind::Await, _)) = desugaring { - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::Await { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }, - ); + err.subdiagnostic(CaptureReasonLabel::Await { + fn_call_span, + place_name: &place_name, + is_partial, + is_loop_message, + }); } else { - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::MethodCall { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }, - ); + err.subdiagnostic(CaptureReasonLabel::MethodCall { + fn_call_span, + place_name: &place_name, + is_partial, + is_loop_message, + }); } // Erase and shadow everything that could be passed to the new infcx. let ty = moved_place.ty(self.body, tcx).ty; @@ -1276,12 +1226,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) && self.infcx.can_eq(self.param_env, ty, self_ty) { - err.subdiagnostic( - self.dcx(), - CaptureReasonSuggest::FreshReborrow { - span: move_span.shrink_to_hi(), - }, - ); + err.subdiagnostic(CaptureReasonSuggest::FreshReborrow { + span: move_span.shrink_to_hi(), + }); has_sugg = true; } if let Some(clone_trait) = tcx.lang_items().clone_trait() { @@ -1368,20 +1315,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } else { if move_span != span || is_loop_message { - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::MovedHere { - move_span, - is_partial, - is_move_msg, - is_loop_message, - }, - ); + err.subdiagnostic(CaptureReasonLabel::MovedHere { + move_span, + is_partial, + is_move_msg, + is_loop_message, + }); } // If the move error occurs due to a loop, don't show // another message for the same span if !is_loop_message { - move_spans.var_subdiag(self.dcx(), err, None, |kind, var_span| match kind { + move_spans.var_subdiag(err, None, |kind, var_span| match kind { hir::ClosureKind::Coroutine(_) => { CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial } } diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 1d844c3d6a29..5a7bca9ab036 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -579,15 +579,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span), None); } - err.subdiagnostic( - self.dcx(), - crate::session_diagnostics::TypeNoCopy::Label { - is_partial_move: false, - ty: place_ty, - place: &place_desc, - span, - }, - ); + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { + is_partial_move: false, + ty: place_ty, + place: &place_desc, + span, + }); } else { binds_to.sort(); binds_to.dedup(); @@ -620,17 +617,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ); } - err.subdiagnostic( - self.dcx(), - crate::session_diagnostics::TypeNoCopy::Label { - is_partial_move: false, - ty: place_ty, - place: &place_desc, - span: use_span, - }, - ); + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { + is_partial_move: false, + ty: place_ty, + place: &place_desc, + span: use_span, + }); - use_spans.args_subdiag(self.dcx(), err, |args_span| { + use_spans.args_subdiag(err, |args_span| { crate::session_diagnostics::CaptureArgLabel::MoveOutPlace { place: place_desc, args_span, @@ -733,15 +727,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.suggest_cloning(err, bind_to.ty, expr, None, None); } - err.subdiagnostic( - self.dcx(), - crate::session_diagnostics::TypeNoCopy::Label { - is_partial_move: false, - ty: bind_to.ty, - place: place_desc, - span: binding_span, - }, - ); + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { + is_partial_move: false, + ty: bind_to.ty, + place: place_desc, + span: binding_span, + }); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 9fd23bc94cf6..e0b18536dd56 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -230,7 +230,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } if suggest { borrow_spans.var_subdiag( - self.dcx(), &mut err, Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }), |_kind, var_span| { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 15a8764aab3c..67c11ff4a5bd 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -631,13 +631,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap(); let upvar_def_span = self.infcx.tcx.hir().span(def_hir); let upvar_span = upvars_map.get(&def_hir).unwrap().span; - diag.subdiagnostic(self.dcx(), VarHereDenote::Defined { span: upvar_def_span }); - diag.subdiagnostic(self.dcx(), VarHereDenote::Captured { span: upvar_span }); + diag.subdiagnostic(VarHereDenote::Defined { span: upvar_def_span }); + diag.subdiagnostic(VarHereDenote::Captured { span: upvar_span }); } } if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() { - diag.subdiagnostic(self.dcx(), VarHereDenote::FnMutInferred { span: fr_span }); + diag.subdiagnostic(VarHereDenote::FnMutInferred { span: fr_span }); } self.suggest_move_on_borrowing_closure(&mut diag); @@ -810,7 +810,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }, }; - diag.subdiagnostic(self.dcx(), err_category); + diag.subdiagnostic(err_category); self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr); self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr); @@ -1008,7 +1008,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ident.span, "calling this method introduces the `impl`'s `'static` requirement", ); - err.subdiagnostic(self.dcx(), RequireStaticErr::UsedImpl { multi_span }); + err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span }); err.span_suggestion_verbose( span.shrink_to_hi(), "consider relaxing the implicit `'static` requirement", diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 1a7961bf70c1..64238e81b266 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -46,7 +46,7 @@ pub fn parse_asm_args<'a>( sp: Span, is_global_asm: bool, ) -> PResult<'a, AsmArgs> { - let dcx = &p.psess.dcx; + let dcx = p.dcx(); if p.token == token::Eof { return Err(dcx.create_err(errors::AsmRequiresTemplate { span: sp })); @@ -307,7 +307,7 @@ pub fn parse_asm_args<'a>( fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) { // Tool-only output let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span }; - p.psess.dcx.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span }); + p.dcx().emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span }); } /// Try to set the provided option in the provided `AsmArgs`. @@ -379,7 +379,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, p.expect(&token::OpenDelim(Delimiter::Parenthesis))?; if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) { - return Err(p.psess.dcx.create_err(errors::NonABI { span: p.token.span })); + return Err(p.dcx().create_err(errors::NonABI { span: p.token.span })); } let mut new_abis = Vec::new(); @@ -390,7 +390,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, } Err(opt_lit) => { let span = opt_lit.map_or(p.token.span, |lit| lit.span); - let mut err = p.psess.dcx.struct_span_err(span, "expected string literal"); + let mut err = p.dcx().struct_span_err(span, "expected string literal"); err.span_label(span, "not a string literal"); return Err(err); } diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index 16184ec75113..58928815e893 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -26,7 +26,7 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) { }; let end_span = parser.token.span; if parser.token != token::Eof { - psess.dcx.emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) }); + psess.dcx().emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) }); continue; } diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index b14eb2b5ee60..ed2f98f2a393 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1,5 +1,5 @@ use rustc_errors::{ - codes::*, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, MultiSpan, + codes::*, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans, SubdiagMessageOp, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -434,7 +434,7 @@ pub(crate) struct EnvNotDefinedWithUserMessage { // Hand-written implementation to support custom user messages. impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for EnvNotDefinedWithUserMessage { #[track_caller] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { #[expect( rustc::untranslatable_diagnostic, reason = "cannot translate user-provided messages" @@ -801,7 +801,7 @@ pub(crate) struct AsmClobberNoReg { } impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AsmClobberNoReg { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { // eager translation as `span_labels` takes `AsRef` let lbl1 = dcx.eagerly_translate_to_string( crate::fluent_generated::builtin_macros_asm_clobber_abi, diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 477e5c8bec53..99d0191958d6 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -3,6 +3,7 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{self as ast, attr, NodeId}; use rustc_ast_pretty::pprust; +use rustc_errors::DiagCtxtHandle; use rustc_expand::base::{parse_macro_name_and_helper_attrs, ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; @@ -38,7 +39,7 @@ enum ProcMacro { struct CollectProcMacros<'a> { macros: Vec, in_root: bool, - dcx: &'a rustc_errors::DiagCtxt, + dcx: DiagCtxtHandle<'a>, source_map: &'a SourceMap, is_proc_macro_crate: bool, is_test_crate: bool, @@ -52,7 +53,7 @@ pub fn inject( is_proc_macro_crate: bool, has_proc_macro_decls: bool, is_test_crate: bool, - dcx: &rustc_errors::DiagCtxt, + dcx: DiagCtxtHandle<'_>, ) { let ecfg = ExpansionConfig::default("proc_macro".to_string(), features); let mut cx = ExtCtxt::new(sess, ecfg, resolver, None); diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index ba4e5cfd1307..9d032eb190a0 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -6,6 +6,7 @@ use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; use rustc_ast::visit::{walk_item, Visitor}; use rustc_ast::{attr, ModKind}; +use rustc_errors::DiagCtxtHandle; use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; @@ -391,7 +392,7 @@ fn get_test_name(i: &ast::Item) -> Option { attr::first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker) } -fn get_test_runner(dcx: &rustc_errors::DiagCtxt, krate: &ast::Crate) -> Option { +fn get_test_runner(dcx: DiagCtxtHandle<'_>, krate: &ast::Crate) -> Option { let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?; let meta_list = test_attr.meta_item_list()?; let span = test_attr.span; diff --git a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs index a73860cf18b2..2093b49ff31a 100644 --- a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs +++ b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs @@ -1,6 +1,7 @@ use std::sync::{Arc, Condvar, Mutex}; use jobserver::HelperThread; +use rustc_errors::DiagCtxtHandle; use rustc_session::Session; // FIXME don't panic when a worker thread panics @@ -46,7 +47,7 @@ impl ConcurrencyLimiter { } } - pub(super) fn acquire(&self, dcx: &rustc_errors::DiagCtxt) -> ConcurrencyLimiterToken { + pub(super) fn acquire(&self, dcx: DiagCtxtHandle<'_>) -> ConcurrencyLimiterToken { let mut state = self.state.lock().unwrap(); loop { state.assert_invariants(); diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index 61e0f203ee0b..ec70fbdddb0f 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -28,7 +28,7 @@ use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; use rustc_data_structures::memmap::Mmap; -use rustc_errors::{DiagCtxt, FatalError}; +use rustc_errors::{DiagCtxtHandle, FatalError}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; @@ -59,7 +59,7 @@ struct LtoData { fn prepare_lto( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, ) -> Result { let export_threshold = match cgcx.lto { // We're just doing LTO for our one crate @@ -179,12 +179,13 @@ pub(crate) fn run_fat( cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> Result, FatalError> { let dcx = cgcx.create_dcx(); - let lto_data = prepare_lto(cgcx, &dcx)?; + let dcx = dcx.handle(); + let lto_data = prepare_lto(cgcx, dcx)?; /*let symbols_below_threshold = lto_data.symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::>();*/ fat_lto( cgcx, - &dcx, + dcx, modules, cached_modules, lto_data.upstream_modules, @@ -195,7 +196,7 @@ pub(crate) fn run_fat( fn fat_lto( cgcx: &CodegenContext, - _dcx: &DiagCtxt, + _dcx: DiagCtxtHandle<'_>, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule, CString)>, diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index 3ea5be1ee562..b9c7f72d0b72 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -4,7 +4,7 @@ use gccjit::OutputKind; use rustc_codegen_ssa::back::link::ensure_removed; use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig}; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; -use rustc_errors::DiagCtxt; +use rustc_errors::DiagCtxtHandle; use rustc_fs_util::link_or_copy; use rustc_session::config::OutputType; use rustc_span::fatal_error::FatalError; @@ -15,7 +15,7 @@ use crate::{GccCodegenBackend, GccContext}; pub(crate) unsafe fn codegen( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result { @@ -166,7 +166,7 @@ pub(crate) unsafe fn codegen( pub(crate) fn link( _cgcx: &CodegenContext, - _dcx: &DiagCtxt, + _dcx: DiagCtxtHandle<'_>, mut _modules: Vec>, ) -> Result, FatalError> { unimplemented!(); diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index aee2b077dba1..6bada3d334ce 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -90,13 +90,13 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { pub(crate) struct MissingFeatures; impl Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::codegen_gcc_target_feature_disable_or_enable); if let Some(span) = self.span { diag.span(span); }; if let Some(missing_features) = self.missing_features { - diag.subdiagnostic(dcx, missing_features); + diag.subdiagnostic(missing_features); } diag.arg("features", self.features.join(", ")); diag diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index b1785e150adc..24856506c464 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -16,13 +16,7 @@ #![allow(internal_features)] #![doc(rust_logo)] #![feature(rustdoc_internals)] -#![feature( - rustc_private, - decl_macro, - never_type, - trusted_len, - hash_raw_entry -)] +#![feature(rustc_private, decl_macro, never_type, trusted_len, hash_raw_entry)] #![allow(broken_intra_doc_links)] #![recursion_limit = "256"] #![warn(rust_2018_idioms)] @@ -104,7 +98,7 @@ use rustc_codegen_ssa::traits::{ use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; -use rustc_errors::{DiagCtxt, ErrorGuaranteed}; +use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; @@ -386,7 +380,7 @@ impl WriteBackendMethods for GccCodegenBackend { unsafe fn optimize( _cgcx: &CodegenContext, - _dcx: &DiagCtxt, + _dcx: DiagCtxtHandle<'_>, module: &ModuleCodegen, config: &ModuleConfig, ) -> Result<(), FatalError> { @@ -411,14 +405,17 @@ impl WriteBackendMethods for GccCodegenBackend { unsafe fn codegen( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result { back::write::codegen(cgcx, dcx, module, config) } - fn prepare_thin(_module: ModuleCodegen, _emit_summary: bool) -> (String, Self::ThinBuffer) { + fn prepare_thin( + _module: ModuleCodegen, + _emit_summary: bool, + ) -> (String, Self::ThinBuffer) { unimplemented!(); } @@ -428,7 +425,7 @@ impl WriteBackendMethods for GccCodegenBackend { fn run_link( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, modules: Vec>, ) -> Result, FatalError> { back::write::link(cgcx, dcx, modules) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index bb7c8fe2ea7a..aff3e3d70760 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -14,7 +14,7 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::memmap::Mmap; -use rustc_errors::{DiagCtxt, FatalError}; +use rustc_errors::{DiagCtxtHandle, FatalError}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; use rustc_middle::dep_graph::WorkProduct; @@ -49,7 +49,7 @@ pub fn crate_type_allows_lto(crate_type: CrateType) -> bool { fn prepare_lto( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, ) -> Result<(Vec, Vec<(SerializedModule, CString)>), FatalError> { let export_threshold = match cgcx.lto { // We're just doing LTO for our one crate @@ -203,10 +203,11 @@ pub(crate) fn run_fat( cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> Result, FatalError> { let dcx = cgcx.create_dcx(); - let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, &dcx)?; + let dcx = dcx.handle(); + let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, dcx)?; let symbols_below_threshold = symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::>(); - fat_lto(cgcx, &dcx, modules, cached_modules, upstream_modules, &symbols_below_threshold) + fat_lto(cgcx, dcx, modules, cached_modules, upstream_modules, &symbols_below_threshold) } /// Performs thin LTO by performing necessary global analysis and returning two @@ -218,7 +219,8 @@ pub(crate) fn run_thin( cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> Result<(Vec>, Vec), FatalError> { let dcx = cgcx.create_dcx(); - let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, &dcx)?; + let dcx = dcx.handle(); + let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, dcx)?; let symbols_below_threshold = symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::>(); if cgcx.opts.cg.linker_plugin_lto.enabled() { @@ -227,7 +229,7 @@ pub(crate) fn run_thin( is deferred to the linker" ); } - thin_lto(cgcx, &dcx, modules, upstream_modules, cached_modules, &symbols_below_threshold) + thin_lto(cgcx, dcx, modules, upstream_modules, cached_modules, &symbols_below_threshold) } pub(crate) fn prepare_thin( @@ -241,7 +243,7 @@ pub(crate) fn prepare_thin( fn fat_lto( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule, CString)>, @@ -436,7 +438,7 @@ impl Drop for Linker<'_> { /// they all go out of scope. fn thin_lto( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, modules: Vec<(String, ThinBuffer)>, serialized_modules: Vec<(SerializedModule, CString)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, @@ -593,7 +595,7 @@ fn thin_lto( pub(crate) fn run_pass_manager( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: &mut ModuleCodegen, thin: bool, ) -> Result<(), FatalError> { @@ -714,10 +716,11 @@ pub unsafe fn optimize_thin_module( cgcx: &CodegenContext, ) -> Result, FatalError> { let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); let module_name = &thin_module.shared.module_names[thin_module.idx]; let tm_factory_config = TargetMachineFactoryConfig::new(cgcx, module_name.to_str().unwrap()); - let tm = (cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&dcx, e))?; + let tm = (cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(dcx, e))?; // Right now the implementation we've got only works over serialized // modules, so we create a fresh new LLVM context and parse the module @@ -725,7 +728,7 @@ pub unsafe fn optimize_thin_module( // crates but for locally codegened modules we may be able to reuse // that LLVM Context and Module. let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); - let llmod_raw = parse_module(llcx, module_name, thin_module.data(), &dcx)? as *const _; + let llmod_raw = parse_module(llcx, module_name, thin_module.data(), dcx)? as *const _; let mut module = ModuleCodegen { module_llvm: ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) }, name: thin_module.name().to_string(), @@ -748,7 +751,7 @@ pub unsafe fn optimize_thin_module( let _timer = cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name()); if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) { - return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule)); + return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } save_temp_bitcode(cgcx, &module, "thin-lto-after-rename"); } @@ -758,7 +761,7 @@ pub unsafe fn optimize_thin_module( .prof .generic_activity_with_arg("LLVM_thin_lto_resolve_weak", thin_module.name()); if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) { - return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule)); + return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve"); } @@ -768,7 +771,7 @@ pub unsafe fn optimize_thin_module( .prof .generic_activity_with_arg("LLVM_thin_lto_internalize", thin_module.name()); if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) { - return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule)); + return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize"); } @@ -777,7 +780,7 @@ pub unsafe fn optimize_thin_module( let _timer = cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name()); if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target) { - return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule)); + return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } save_temp_bitcode(cgcx, &module, "thin-lto-after-import"); } @@ -789,7 +792,7 @@ pub unsafe fn optimize_thin_module( // little differently. { info!("running thin lto passes over {}", module.name); - run_pass_manager(cgcx, &dcx, &mut module, true)?; + run_pass_manager(cgcx, dcx, &mut module, true)?; save_temp_bitcode(cgcx, &module, "thin-lto-after-pm"); } } @@ -859,7 +862,7 @@ pub fn parse_module<'a>( cx: &'a llvm::Context, name: &CStr, data: &[u8], - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, ) -> Result<&'a llvm::Module, FatalError> { unsafe { llvm::LLVMRustParseBitcodeForLTO(cx, data.as_ptr(), data.len(), name.as_ptr()) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 02e3bb06dda3..bbfc697407bf 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -26,7 +26,7 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_errors::{DiagCtxt, FatalError, Level}; +use rustc_errors::{DiagCtxtHandle, FatalError, Level}; use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_middle::ty::TyCtxt; use rustc_session::config::{self, Lto, OutputType, Passes}; @@ -47,7 +47,7 @@ use std::slice; use std::str; use std::sync::Arc; -pub fn llvm_err<'a>(dcx: &rustc_errors::DiagCtxt, err: LlvmError<'a>) -> FatalError { +pub fn llvm_err<'a>(dcx: DiagCtxtHandle<'_>, err: LlvmError<'a>) -> FatalError { match llvm::last_error() { Some(llvm_err) => dcx.emit_almost_fatal(WithLlvmError(err, llvm_err)), None => dcx.emit_almost_fatal(err), @@ -55,7 +55,7 @@ pub fn llvm_err<'a>(dcx: &rustc_errors::DiagCtxt, err: LlvmError<'a>) -> FatalEr } pub fn write_output_file<'ll>( - dcx: &rustc_errors::DiagCtxt, + dcx: DiagCtxtHandle<'_>, target: &'ll llvm::TargetMachine, pm: &llvm::PassManager<'ll>, m: &'ll llvm::Module, @@ -331,7 +331,7 @@ pub enum CodegenDiagnosticsStage { } pub struct DiagnosticHandlers<'a> { - data: *mut (&'a CodegenContext, &'a DiagCtxt), + data: *mut (&'a CodegenContext, DiagCtxtHandle<'a>), llcx: &'a llvm::Context, old_handler: Option<&'a llvm::DiagnosticHandler>, } @@ -339,7 +339,7 @@ pub struct DiagnosticHandlers<'a> { impl<'a> DiagnosticHandlers<'a> { pub fn new( cgcx: &'a CodegenContext, - dcx: &'a DiagCtxt, + dcx: DiagCtxtHandle<'a>, llcx: &'a llvm::Context, module: &ModuleCodegen, stage: CodegenDiagnosticsStage, @@ -428,7 +428,7 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void if user.is_null() { return; } - let (cgcx, dcx) = *(user as *const (&CodegenContext, &DiagCtxt)); + let (cgcx, dcx) = *(user as *const (&CodegenContext, DiagCtxtHandle<'_>)); match llvm::diagnostic::Diagnostic::unpack(info) { llvm::diagnostic::InlineAsm(inline) => { @@ -506,7 +506,7 @@ fn get_instr_profile_output_path(config: &ModuleConfig) -> Option { pub(crate) unsafe fn llvm_optimize( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: &ModuleCodegen, config: &ModuleConfig, opt_level: config::OptLevel, @@ -604,7 +604,7 @@ pub(crate) unsafe fn llvm_optimize( // Unsafe due to LLVM calls. pub(crate) unsafe fn optimize( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: &ModuleCodegen, config: &ModuleConfig, ) -> Result<(), FatalError> { @@ -637,7 +637,7 @@ pub(crate) unsafe fn optimize( pub(crate) fn link( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, mut modules: Vec>, ) -> Result, FatalError> { use super::lto::{Linker, ModuleBuffer}; @@ -660,7 +660,7 @@ pub(crate) fn link( pub(crate) unsafe fn codegen( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result { diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 9d83dc811633..40ac2f9c8bab 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -4,7 +4,7 @@ use std::path::Path; use crate::fluent_generated as fluent; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_errors::{Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -100,7 +100,7 @@ pub(crate) struct DynamicLinkingWithLTO; pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>); impl Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let diag: Diag<'_, G> = self.0.into_diag(dcx, level); let (message, _) = diag.messages.first().expect("`LlvmError` with no message"); let message = dcx.eagerly_translate_to_string(message.clone(), diag.args.iter()); @@ -120,13 +120,13 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { pub(crate) struct MissingFeatures; impl Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::codegen_llvm_target_feature_disable_or_enable); if let Some(span) = self.span { diag.span(span); }; if let Some(missing_features) = self.missing_features { - diag.subdiagnostic(dcx, missing_features); + diag.subdiagnostic(missing_features); } diag.arg("features", self.features.join(", ")); diag @@ -180,7 +180,7 @@ pub enum LlvmError<'a> { pub(crate) struct WithLlvmError<'a>(pub LlvmError<'a>, pub String); impl Diagnostic<'_, G> for WithLlvmError<'_> { - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { use LlvmError::*; let msg_with_llvm_err = match &self.0 { WriteOutput { .. } => fluent::codegen_llvm_write_output_with_llvm_err, diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index bb76d3883934..4b7a26430071 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -31,7 +31,7 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::{CodegenResults, CompiledModule}; use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::{DiagCtxt, ErrorGuaranteed, FatalError}; +use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; @@ -191,7 +191,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { } fn run_link( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, modules: Vec>, ) -> Result, FatalError> { back::write::link(cgcx, dcx, modules) @@ -212,7 +212,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { } unsafe fn optimize( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: &ModuleCodegen, config: &ModuleConfig, ) -> Result<(), FatalError> { @@ -223,7 +223,8 @@ impl WriteBackendMethods for LlvmCodegenBackend { module: &mut ModuleCodegen, ) -> Result<(), FatalError> { let dcx = cgcx.create_dcx(); - back::lto::run_pass_manager(cgcx, &dcx, module, false) + let dcx = dcx.handle(); + back::lto::run_pass_manager(cgcx, dcx, module, false) } unsafe fn optimize_thin( cgcx: &CodegenContext, @@ -233,7 +234,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { } unsafe fn codegen( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result { @@ -441,7 +442,7 @@ impl ModuleLlvm { cgcx: &CodegenContext, name: &CStr, buffer: &[u8], - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, ) -> Result { unsafe { let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index bdb808b1d4ff..c352100b01b1 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3,7 +3,7 @@ use rustc_ast::CRATE_NODE_ID; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_errors::{DiagCtxt, ErrorGuaranteed, FatalError}; +use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError}; use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_metadata::find_native_static_library; @@ -54,7 +54,7 @@ use std::process::{ExitStatus, Output, Stdio}; use std::{env, fmt, fs, io, mem, str}; use tracing::{debug, info, warn}; -pub fn ensure_removed(dcx: &DiagCtxt, path: &Path) { +pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) { if let Err(e) = fs::remove_file(path) { if e.kind() != io::ErrorKind::NotFound { dcx.err(format!("failed to remove {}: {}", path.display(), e)); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index dec87db0fc5c..064be4988bdd 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -891,9 +891,10 @@ fn execute_optimize_work_item( module_config: &ModuleConfig, ) -> Result, FatalError> { let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); unsafe { - B::optimize(cgcx, &dcx, &module, module_config)?; + B::optimize(cgcx, dcx, &module, module_config)?; } // After we've done the initial round of optimizations we need to @@ -954,7 +955,11 @@ fn execute_copy_from_cache_work_item( match link_or_copy(&source_file, &output_path) { Ok(_) => Some(output_path), Err(error) => { - cgcx.create_dcx().emit_err(errors::CopyPathBuf { source_file, output_path, error }); + cgcx.create_dcx().handle().emit_err(errors::CopyPathBuf { + source_file, + output_path, + error, + }); None } } @@ -987,7 +992,7 @@ fn execute_copy_from_cache_work_item( let bytecode = load_from_incr_cache(module_config.emit_bc, OutputType::Bitcode); let object = load_from_incr_cache(should_emit_obj, OutputType::Object); if should_emit_obj && object.is_none() { - cgcx.create_dcx().emit_fatal(errors::NoSavedObjectFile { cgu_name: &module.name }) + cgcx.create_dcx().handle().emit_fatal(errors::NoSavedObjectFile { cgu_name: &module.name }) } WorkItemResult::Finished(CompiledModule { @@ -1016,12 +1021,13 @@ fn finish_intra_module_work( module_config: &ModuleConfig, ) -> Result, FatalError> { let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); if !cgcx.opts.unstable_opts.combine_cgu || module.kind == ModuleKind::Metadata || module.kind == ModuleKind::Allocator { - let module = unsafe { B::codegen(cgcx, &dcx, module, module_config)? }; + let module = unsafe { B::codegen(cgcx, dcx, module, module_config)? }; Ok(WorkItemResult::Finished(module)) } else { Ok(WorkItemResult::NeedsLink(module)) @@ -1692,9 +1698,10 @@ fn start_executing_work( if !needs_link.is_empty() { assert!(compiled_modules.is_empty()); let dcx = cgcx.create_dcx(); - let module = B::run_link(&cgcx, &dcx, needs_link).map_err(|_| ())?; + let dcx = dcx.handle(); + let module = B::run_link(&cgcx, dcx, needs_link).map_err(|_| ())?; let module = unsafe { - B::codegen(&cgcx, &dcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())? + B::codegen(&cgcx, dcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())? }; compiled_modules.push(module); } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 3641e7842cfb..e6ba31c51650 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -4,7 +4,7 @@ use crate::assert_module_sources::CguReuse; use crate::back::command::Command; use crate::fluent_generated as fluent; use rustc_errors::{ - codes::*, Diag, DiagArgValue, DiagCtxt, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, + codes::*, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, }; use rustc_macros::Diagnostic; use rustc_middle::ty::layout::LayoutError; @@ -215,7 +215,7 @@ pub enum LinkRlibError { pub struct ThorinErrorWrapper(pub thorin::Error); impl Diagnostic<'_, G> for ThorinErrorWrapper { - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let build = |msg| Diag::new(dcx, level, msg); match self.0 { thorin::Error::ReadInput(_) => build(fluent::codegen_ssa_thorin_read_input_failure), @@ -348,7 +348,7 @@ pub struct LinkingFailed<'a> { } impl Diagnostic<'_, G> for LinkingFailed<'_> { - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_linking_failed); diag.arg("linker_path", format!("{}", self.linker_path.display())); diag.arg("exit_status", format!("{}", self.exit_status)); diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index f83e34ab01bc..f4b1421a5329 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -2,7 +2,7 @@ use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig}; use crate::{CompiledModule, ModuleCodegen}; -use rustc_errors::{DiagCtxt, FatalError}; +use rustc_errors::{DiagCtxtHandle, FatalError}; use rustc_middle::dep_graph::WorkProduct; pub trait WriteBackendMethods: 'static + Sized + Clone { @@ -16,7 +16,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { /// Merge all modules into main_module and returning it fn run_link( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, modules: Vec>, ) -> Result, FatalError>; /// Performs fat LTO by merging all modules into a single one and returning it @@ -38,7 +38,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { fn print_statistics(&self); unsafe fn optimize( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: &ModuleCodegen, config: &ModuleConfig, ) -> Result<(), FatalError>; @@ -52,7 +52,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { ) -> Result, FatalError>; unsafe fn codegen( cgcx: &CodegenContext, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result; diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index 308b90cd470d..ac8f0d842ee4 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -5,7 +5,7 @@ //! it finds operations that are invalid in a certain context. use rustc_attr as attr; -use rustc_errors::DiagCtxt; +use rustc_errors::DiagCtxtHandle; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::bug; @@ -46,7 +46,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { ConstCx { body, tcx, param_env, const_kind } } - pub(crate) fn dcx(&self) -> &'tcx DiagCtxt { + pub(crate) fn dcx(&self) -> DiagCtxtHandle<'tcx> { self.tcx.dcx() } diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index eb9a83fb9cfa..55432e63ef9d 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -138,7 +138,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { // FIXME(effects) revisit this if !tcx.is_const_trait_impl_raw(data.impl_def_id) { let span = tcx.def_span(data.impl_def_id); - err.subdiagnostic(tcx.dcx(), errors::NonConstImplNote { span }); + err.subdiagnostic(errors::NonConstImplNote { span }); } } } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 91d17fdd8959..5fa48a59794b 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use either::Either; use rustc_errors::{ - codes::*, Diag, DiagArgValue, DiagCtxt, DiagMessage, Diagnostic, EmissionGuarantee, Level, + codes::*, Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level, }; use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -453,7 +453,7 @@ pub trait ReportErrorExt { } } -fn bad_pointer_message(msg: CheckInAllocMsg, dcx: &DiagCtxt) -> String { +fn bad_pointer_message(msg: CheckInAllocMsg, dcx: DiagCtxtHandle<'_>) -> String { use crate::fluent_generated::*; let msg = match msg { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 86325c5ae240..f602d989e080 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -4,7 +4,7 @@ use std::{fmt, mem}; use either::{Either, Left, Right}; use tracing::{debug, info, info_span, instrument, trace}; -use rustc_errors::DiagCtxt; +use rustc_errors::DiagCtxtHandle; use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::IndexVec; use rustc_middle::mir; @@ -474,7 +474,7 @@ pub(super) fn from_known_layout<'tcx>( /// /// This is NOT the preferred way to render an error; use `report` from `const_eval` instead. /// However, this is useful when error messages appear in ICEs. -pub fn format_interp_error<'tcx>(dcx: &DiagCtxt, e: InterpErrorInfo<'tcx>) -> String { +pub fn format_interp_error<'tcx>(dcx: DiagCtxtHandle<'_>, e: InterpErrorInfo<'tcx>) -> String { let (e, backtrace) = e.into_parts(); backtrace.print_backtrace(); // FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 9acff4a0a26c..5ffa3a6099c0 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1444,6 +1444,7 @@ fn report_ice( fallback_bundle, )); let dcx = rustc_errors::DiagCtxt::new(emitter); + let dcx = dcx.handle(); // a .span_bug or .bug call has already printed what // it wants to print. @@ -1509,7 +1510,7 @@ fn report_ice( let num_frames = if backtrace { None } else { Some(2) }; - interface::try_print_query_stack(&dcx, num_frames, file); + interface::try_print_query_stack(dcx, num_frames, file); // We don't trust this callback not to panic itself, so run it at the end after we're sure we've // printed all the relevant info. diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 34b569c42068..e580910af779 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1,7 +1,7 @@ use crate::snippet::Style; use crate::{ - CodeSuggestion, DiagCtxt, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level, MultiSpan, - StashKey, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle, + CodeSuggestion, DiagCtxtHandle, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level, + MultiSpan, StashKey, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle, }; use rustc_data_structures::fx::FxIndexMap; use rustc_error_messages::fluent_value_from_str_list_sep_by_and; @@ -133,7 +133,7 @@ impl EmissionGuarantee for rustc_span::fatal_error::FatalError { pub trait Diagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> { /// Write out as a diagnostic out of `DiagCtxt`. #[must_use] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G>; + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G>; } impl<'a, T, G> Diagnostic<'a, G> for Spanned @@ -141,7 +141,7 @@ where T: Diagnostic<'a, G>, G: EmissionGuarantee, { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { self.node.into_diag(dcx, level).with_span(self.span) } } @@ -490,7 +490,7 @@ pub struct Subdiag { /// the methods of `Diag` here, consider extending `DiagCtxtFlags`. #[must_use] pub struct Diag<'a, G: EmissionGuarantee = ErrorGuaranteed> { - pub dcx: &'a DiagCtxt, + pub dcx: DiagCtxtHandle<'a>, /// Why the `Option`? It is always `Some` until the `Diag` is consumed via /// `emit`, `cancel`, etc. At that point it is consumed and replaced with @@ -578,13 +578,13 @@ macro_rules! with_fn { impl<'a, G: EmissionGuarantee> Diag<'a, G> { #[rustc_lint_diagnostics] #[track_caller] - pub fn new(dcx: &'a DiagCtxt, level: Level, message: impl Into) -> Self { + pub fn new(dcx: DiagCtxtHandle<'a>, level: Level, message: impl Into) -> Self { Self::new_diagnostic(dcx, DiagInner::new(level, message)) } /// Creates a new `Diag` with an already constructed diagnostic. #[track_caller] - pub(crate) fn new_diagnostic(dcx: &'a DiagCtxt, diag: DiagInner) -> Self { + pub(crate) fn new_diagnostic(dcx: DiagCtxtHandle<'a>, diag: DiagInner) -> Self { debug!("Created new diagnostic"); Self { dcx, diag: Some(Box::new(diag)), _marker: PhantomData } } @@ -1192,11 +1192,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { /// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of /// interpolated variables). #[rustc_lint_diagnostics] - pub fn subdiagnostic( - &mut self, - dcx: &crate::DiagCtxt, - subdiagnostic: impl Subdiagnostic, - ) -> &mut Self { + pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self { + let dcx = self.dcx; subdiagnostic.add_to_diag_with(self, &|diag, msg| { let args = diag.args.iter(); let msg = diag.subdiagnostic_message_to_diagnostic_message(msg); @@ -1341,7 +1338,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { /// See `DiagCtxt::stash_diagnostic` for details. pub fn stash(mut self, span: Span, key: StashKey) -> Option { - self.dcx.stash_diagnostic(span, key, self.take_diag()) + let diag = self.take_diag(); + self.dcx.stash_diagnostic(span, key, diag) } /// Delay emission of this diagnostic as a bug. diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index ee6df8e15db8..0af80bc5c67b 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -1,7 +1,7 @@ use crate::diagnostic::DiagLocation; -use crate::{fluent_generated as fluent, Subdiagnostic}; +use crate::{fluent_generated as fluent, DiagCtxtHandle, Subdiagnostic}; use crate::{ - Diag, DiagArgValue, DiagCtxt, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level, + Diag, DiagArgValue, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level, SubdiagMessageOp, }; use rustc_ast as ast; @@ -315,7 +315,7 @@ impl IntoDiagArg for DiagSymbolList { } impl Diagnostic<'_, G> for TargetDataLayoutErrors<'_> { - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { match self { TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => { Diag::new(dcx, level, fluent::errors_target_invalid_address_space) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 5d4d2555100e..245deda50d5c 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -567,7 +567,7 @@ impl Emitter for SilentEmitter { if let Some(fatal_note) = &self.fatal_note { diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new()); } - self.fatal_dcx.emit_diagnostic(diag); + self.fatal_dcx.handle().emit_diagnostic(diag); } } } diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs index 80b4d2bf75c0..e4b29fc9103d 100644 --- a/compiler/rustc_errors/src/json/tests.rs +++ b/compiler/rustc_errors/src/json/tests.rs @@ -55,8 +55,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) { ); let span = Span::with_root_ctxt(BytePos(span.0), BytePos(span.1)); - let dcx = DiagCtxt::new(Box::new(je)); - dcx.span_err(span, "foo"); + DiagCtxt::new(Box::new(je)).handle().span_err(span, "foo"); let bytes = output.lock().unwrap(); let actual_output = str::from_utf8(&bytes).unwrap(); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 4dc5d84b318b..83d5bbff0b0a 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -414,6 +414,19 @@ pub struct DiagCtxt { inner: Lock, } +#[derive(Copy, Clone)] +pub struct DiagCtxtHandle<'a> { + dcx: &'a DiagCtxt, +} + +impl<'a> std::ops::Deref for DiagCtxtHandle<'a> { + type Target = &'a DiagCtxt; + + fn deref(&self) -> &Self::Target { + &self.dcx + } +} + /// This inner struct exists to keep it all behind a single lock; /// this is done to prevent possible deadlocks in a multi-threaded compiler, /// as well as inconsistent state observation. @@ -608,7 +621,7 @@ impl DiagCtxt { } pub fn make_silent( - &mut self, + &self, fallback_bundle: LazyFallbackBundle, fatal_note: Option, emit_fatal_diagnostic: bool, @@ -623,7 +636,7 @@ impl DiagCtxt { }); } - fn wrap_emitter(&mut self, f: F) + fn wrap_emitter(&self, f: F) where F: FnOnce(DiagCtxtInner) -> Box, { @@ -738,6 +751,12 @@ impl DiagCtxt { *fulfilled_expectations = Default::default(); } + pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> { + DiagCtxtHandle { dcx: self } + } +} + +impl<'a> DiagCtxtHandle<'a> { /// Stashes a diagnostic for possible later improvement in a different, /// later stage of the compiler. Possible actions depend on the diagnostic /// level: @@ -745,8 +764,8 @@ impl DiagCtxt { /// - Level::Error: immediately counted as an error that has occurred, because it /// is guaranteed to be emitted eventually. Can be later accessed with the /// provided `span` and `key` through - /// [`DiagCtxt::try_steal_modify_and_emit_err`] or - /// [`DiagCtxt::try_steal_replace_and_emit_err`]. These do not allow + /// [`DiagCtxtHandle::try_steal_modify_and_emit_err`] or + /// [`DiagCtxtHandle::try_steal_replace_and_emit_err`]. These do not allow /// cancellation or downgrading of the error. Returns /// `Some(ErrorGuaranteed)`. /// - Level::DelayedBug: this does happen occasionally with errors that are @@ -757,7 +776,7 @@ impl DiagCtxt { /// user-facing error. Returns `Some(ErrorGuaranteed)` as is normal for /// delayed bugs. /// - Level::Warning and lower (i.e. !is_error()): can be accessed with the - /// provided `span` and `key` through [`DiagCtxt::steal_non_err()`]. This + /// provided `span` and `key` through [`DiagCtxtHandle::steal_non_err()`]. This /// allows cancelling and downgrading of the diagnostic. Returns `None`. pub fn stash_diagnostic( &self, @@ -793,7 +812,7 @@ impl DiagCtxt { /// Steal a previously stashed non-error diagnostic with the given `Span` /// and [`StashKey`] as the key. Panics if the found diagnostic is an /// error. - pub fn steal_non_err(&self, span: Span, key: StashKey) -> Option> { + pub fn steal_non_err(self, span: Span, key: StashKey) -> Option> { let key = (span.with_parent(None), key); // FIXME(#120456) - is `swap_remove` correct? let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.swap_remove(&key)?; @@ -807,7 +826,7 @@ impl DiagCtxt { /// no matching diagnostic is found. Panics if the found diagnostic's level /// isn't `Level::Error`. pub fn try_steal_modify_and_emit_err( - &self, + self, span: Span, key: StashKey, mut modify_err: F, @@ -833,7 +852,7 @@ impl DiagCtxt { /// [`StashKey`] as the key, cancels it if found, and emits `new_err`. /// Panics if the found diagnostic's level isn't `Level::Error`. pub fn try_steal_replace_and_emit_err( - &self, + self, span: Span, key: StashKey, new_err: Diag<'_>, @@ -1106,18 +1125,18 @@ impl DiagCtxt { // // Functions beginning with `struct_`/`create_` create a diagnostic. Other // functions create and emit a diagnostic all in one go. -impl DiagCtxt { +impl<'a> DiagCtxtHandle<'a> { // No `#[rustc_lint_diagnostics]` and no `impl Into` because bug messages aren't // user-facing. #[track_caller] - pub fn struct_bug(&self, msg: impl Into>) -> Diag<'_, BugAbort> { + pub fn struct_bug(self, msg: impl Into>) -> Diag<'a, BugAbort> { Diag::new(self, Bug, msg.into()) } // No `#[rustc_lint_diagnostics]` and no `impl Into` because bug messages aren't // user-facing. #[track_caller] - pub fn bug(&self, msg: impl Into>) -> ! { + pub fn bug(self, msg: impl Into>) -> ! { self.struct_bug(msg).emit() } @@ -1125,111 +1144,108 @@ impl DiagCtxt { // user-facing. #[track_caller] pub fn struct_span_bug( - &self, + self, span: impl Into, msg: impl Into>, - ) -> Diag<'_, BugAbort> { + ) -> Diag<'a, BugAbort> { self.struct_bug(msg).with_span(span) } // No `#[rustc_lint_diagnostics]` and no `impl Into` because bug messages aren't // user-facing. #[track_caller] - pub fn span_bug(&self, span: impl Into, msg: impl Into>) -> ! { + pub fn span_bug(self, span: impl Into, msg: impl Into>) -> ! { self.struct_span_bug(span, msg.into()).emit() } #[track_caller] - pub fn create_bug<'a>(&'a self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> { + pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> { bug.into_diag(self, Bug) } #[track_caller] - pub fn emit_bug<'a>(&'a self, bug: impl Diagnostic<'a, BugAbort>) -> ! { + pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! { self.create_bug(bug).emit() } #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_fatal(&self, msg: impl Into) -> Diag<'_, FatalAbort> { + pub fn struct_fatal(self, msg: impl Into) -> Diag<'a, FatalAbort> { Diag::new(self, Fatal, msg) } #[rustc_lint_diagnostics] #[track_caller] - pub fn fatal(&self, msg: impl Into) -> ! { + pub fn fatal(self, msg: impl Into) -> ! { self.struct_fatal(msg).emit() } #[rustc_lint_diagnostics] #[track_caller] pub fn struct_span_fatal( - &self, + self, span: impl Into, msg: impl Into, - ) -> Diag<'_, FatalAbort> { + ) -> Diag<'a, FatalAbort> { self.struct_fatal(msg).with_span(span) } #[rustc_lint_diagnostics] #[track_caller] - pub fn span_fatal(&self, span: impl Into, msg: impl Into) -> ! { + pub fn span_fatal(self, span: impl Into, msg: impl Into) -> ! { self.struct_span_fatal(span, msg).emit() } #[track_caller] - pub fn create_fatal<'a>( - &'a self, - fatal: impl Diagnostic<'a, FatalAbort>, - ) -> Diag<'a, FatalAbort> { + pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> { fatal.into_diag(self, Fatal) } #[track_caller] - pub fn emit_fatal<'a>(&'a self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! { + pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! { self.create_fatal(fatal).emit() } #[track_caller] - pub fn create_almost_fatal<'a>( - &'a self, + pub fn create_almost_fatal( + self, fatal: impl Diagnostic<'a, FatalError>, ) -> Diag<'a, FatalError> { fatal.into_diag(self, Fatal) } #[track_caller] - pub fn emit_almost_fatal<'a>(&'a self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError { + pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError { self.create_almost_fatal(fatal).emit() } // FIXME: This method should be removed (every error should have an associated error code). #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_err(&self, msg: impl Into) -> Diag<'_> { + pub fn struct_err(self, msg: impl Into) -> Diag<'a> { Diag::new(self, Error, msg) } #[rustc_lint_diagnostics] #[track_caller] - pub fn err(&self, msg: impl Into) -> ErrorGuaranteed { + pub fn err(self, msg: impl Into) -> ErrorGuaranteed { self.struct_err(msg).emit() } #[rustc_lint_diagnostics] #[track_caller] pub fn struct_span_err( - &self, + self, span: impl Into, msg: impl Into, - ) -> Diag<'_> { + ) -> Diag<'a> { self.struct_err(msg).with_span(span) } #[rustc_lint_diagnostics] #[track_caller] pub fn span_err( - &self, + self, span: impl Into, msg: impl Into, ) -> ErrorGuaranteed { @@ -1237,12 +1253,12 @@ impl DiagCtxt { } #[track_caller] - pub fn create_err<'a>(&'a self, err: impl Diagnostic<'a>) -> Diag<'a> { + pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> { err.into_diag(self, Error) } #[track_caller] - pub fn emit_err<'a>(&'a self, err: impl Diagnostic<'a>) -> ErrorGuaranteed { + pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed { self.create_err(err).emit() } @@ -1251,7 +1267,7 @@ impl DiagCtxt { // No `#[rustc_lint_diagnostics]` and no `impl Into` because bug messages aren't // user-facing. #[track_caller] - pub fn delayed_bug(&self, msg: impl Into>) -> ErrorGuaranteed { + pub fn delayed_bug(self, msg: impl Into>) -> ErrorGuaranteed { Diag::::new(self, DelayedBug, msg.into()).emit() } @@ -1264,7 +1280,7 @@ impl DiagCtxt { // user-facing. #[track_caller] pub fn span_delayed_bug( - &self, + self, sp: impl Into, msg: impl Into>, ) -> ErrorGuaranteed { @@ -1273,45 +1289,45 @@ impl DiagCtxt { #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_warn(&self, msg: impl Into) -> Diag<'_, ()> { + pub fn struct_warn(self, msg: impl Into) -> Diag<'a, ()> { Diag::new(self, Warning, msg) } #[rustc_lint_diagnostics] #[track_caller] - pub fn warn(&self, msg: impl Into) { + pub fn warn(self, msg: impl Into) { self.struct_warn(msg).emit() } #[rustc_lint_diagnostics] #[track_caller] pub fn struct_span_warn( - &self, + self, span: impl Into, msg: impl Into, - ) -> Diag<'_, ()> { + ) -> Diag<'a, ()> { self.struct_warn(msg).with_span(span) } #[rustc_lint_diagnostics] #[track_caller] - pub fn span_warn(&self, span: impl Into, msg: impl Into) { + pub fn span_warn(self, span: impl Into, msg: impl Into) { self.struct_span_warn(span, msg).emit() } #[track_caller] - pub fn create_warn<'a>(&'a self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> { + pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> { warning.into_diag(self, Warning) } #[track_caller] - pub fn emit_warn<'a>(&'a self, warning: impl Diagnostic<'a, ()>) { + pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) { self.create_warn(warning).emit() } #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_note(&self, msg: impl Into) -> Diag<'_, ()> { + pub fn struct_note(self, msg: impl Into) -> Diag<'a, ()> { Diag::new(self, Note, msg) } @@ -1324,54 +1340,50 @@ impl DiagCtxt { #[rustc_lint_diagnostics] #[track_caller] pub fn struct_span_note( - &self, + self, span: impl Into, msg: impl Into, - ) -> Diag<'_, ()> { + ) -> Diag<'a, ()> { self.struct_note(msg).with_span(span) } #[rustc_lint_diagnostics] #[track_caller] - pub fn span_note(&self, span: impl Into, msg: impl Into) { + pub fn span_note(self, span: impl Into, msg: impl Into) { self.struct_span_note(span, msg).emit() } #[track_caller] - pub fn create_note<'a>(&'a self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> { + pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> { note.into_diag(self, Note) } #[track_caller] - pub fn emit_note<'a>(&'a self, note: impl Diagnostic<'a, ()>) { + pub fn emit_note(self, note: impl Diagnostic<'a, ()>) { self.create_note(note).emit() } #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_help(&self, msg: impl Into) -> Diag<'_, ()> { + pub fn struct_help(self, msg: impl Into) -> Diag<'a, ()> { Diag::new(self, Help, msg) } #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_failure_note(&self, msg: impl Into) -> Diag<'_, ()> { + pub fn struct_failure_note(self, msg: impl Into) -> Diag<'a, ()> { Diag::new(self, FailureNote, msg) } #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_allow(&self, msg: impl Into) -> Diag<'_, ()> { + pub fn struct_allow(self, msg: impl Into) -> Diag<'a, ()> { Diag::new(self, Allow, msg) } #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_expect( - &self, - msg: impl Into, - id: LintExpectationId, - ) -> Diag<'_, ()> { + pub fn struct_expect(self, msg: impl Into, id: LintExpectationId) -> Diag<'a, ()> { Diag::new(self, Expect(id), msg) } } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b3f6a35f3a4b..ddc6490ac0c5 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -12,7 +12,7 @@ use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind use rustc_attr::{self as attr, Deprecation, Stability}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{self, Lrc}; -use rustc_errors::{DiagCtxt, ErrorGuaranteed, PResult}; +use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult}; use rustc_feature::Features; use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools}; use rustc_parse::{parser::Parser, MACRO_ARGUMENTS}; @@ -1135,7 +1135,7 @@ impl<'a> ExtCtxt<'a> { } } - pub fn dcx(&self) -> &'a DiagCtxt { + pub fn dcx(&self) -> DiagCtxtHandle<'a> { self.sess.dcx() } @@ -1256,7 +1256,7 @@ pub fn resolve_path(sess: &Session, path: impl Into, span: Span) -> PRe } pub fn parse_macro_name_and_helper_attrs( - dcx: &rustc_errors::DiagCtxt, + dcx: DiagCtxtHandle<'_>, attr: &Attribute, macro_type: &str, ) -> Option<(Symbol, Vec)> { @@ -1358,7 +1358,7 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) { if crate_matches { // FIXME: make this translatable #[allow(rustc::untranslatable_diagnostic)] - sess.psess.dcx.emit_fatal(errors::ProcMacroBackCompat { + sess.dcx().emit_fatal(errors::ProcMacroBackCompat { crate_name: "rental".to_string(), fixed_version: "0.5.6".to_string(), }); diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 442fd654b6ae..bf475c1dc96f 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -7,7 +7,7 @@ use crate::mbe::{ use rustc_ast::token::{self, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; -use rustc_errors::{Applicability, Diag, DiagCtxt, DiagMessage}; +use rustc_errors::{Applicability, Diag, DiagMessage}; use rustc_macros::Subdiagnostic; use rustc_parse::parser::{Parser, Recovery}; use rustc_span::source_map::SourceMap; @@ -61,7 +61,7 @@ pub(super) fn failed_to_match_macro<'cx>( err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro"); } - annotate_doc_comment(cx.sess.dcx(), &mut err, psess.source_map(), span); + annotate_doc_comment(&mut err, psess.source_map(), span); if let Some(span) = remaining_matcher.span() { err.span_note(span, format!("while trying to match {remaining_matcher}")); @@ -324,12 +324,12 @@ enum ExplainDocComment { }, } -pub(super) fn annotate_doc_comment(dcx: &DiagCtxt, err: &mut Diag<'_>, sm: &SourceMap, span: Span) { +pub(super) fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Span) { if let Ok(src) = sm.span_to_snippet(span) { if src.starts_with("///") || src.starts_with("/**") { - err.subdiagnostic(dcx, ExplainDocComment::Outer { span }); + err.subdiagnostic(ExplainDocComment::Outer { span }); } else if src.starts_with("//!") || src.starts_with("/*!") { - err.subdiagnostic(dcx, ExplainDocComment::Inner { span }); + err.subdiagnostic(ExplainDocComment::Inner { span }); } } } diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 72dbbde54b31..d9a945a32150 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -206,7 +206,7 @@ pub(super) fn check_meta_variables( rhses: &[TokenTree], ) -> Result<(), ErrorGuaranteed> { if lhses.len() != rhses.len() { - psess.dcx.span_bug(span, "length mismatch between LHSes and RHSes") + psess.dcx().span_bug(span, "length mismatch between LHSes and RHSes") } let mut guar = None; for (lhs, rhs) in iter::zip(lhses, rhses) { @@ -245,7 +245,7 @@ fn check_binders( // MetaVar(fragment) and not as MetaVarDecl(y, fragment). TokenTree::MetaVar(span, name) => { if macros.is_empty() { - psess.dcx.span_bug(span, "unexpected MetaVar in lhs"); + psess.dcx().span_bug(span, "unexpected MetaVar in lhs"); } let name = MacroRulesNormalizedIdent::new(name); // There are 3 possibilities: @@ -276,7 +276,7 @@ fn check_binders( ); } if !macros.is_empty() { - psess.dcx.span_bug(span, "unexpected MetaVarDecl in nested lhs"); + psess.dcx().span_bug(span, "unexpected MetaVarDecl in nested lhs"); } let name = MacroRulesNormalizedIdent::new(name); if let Some(prev_info) = get_binder_info(macros, binders, name) { @@ -284,7 +284,7 @@ fn check_binders( // for nested macro definitions. *guar = Some( psess - .dcx + .dcx() .emit_err(errors::DuplicateMatcherBinding { span, prev: prev_info.span }), ); } else { @@ -344,7 +344,7 @@ fn check_occurrences( match *rhs { TokenTree::Token(..) => {} TokenTree::MetaVarDecl(span, _name, _kind) => { - psess.dcx.span_bug(span, "unexpected MetaVarDecl in rhs") + psess.dcx().span_bug(span, "unexpected MetaVarDecl in rhs") } TokenTree::MetaVar(span, name) => { let name = MacroRulesNormalizedIdent::new(name); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 5d3ba5d32230..49b1f5ce0e3e 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -383,7 +383,7 @@ pub fn compile_declarative_macro( }; let dummy_syn_ext = |guar| (mk_syn_ext(Box::new(DummyExpander(guar))), Vec::new()); - let dcx = &sess.psess.dcx; + let dcx = sess.dcx(); let lhs_nm = Ident::new(sym::lhs, def.span); let rhs_nm = Ident::new(sym::rhs, def.span); let tt_spec = Some(NonterminalKind::TT); @@ -463,7 +463,7 @@ pub fn compile_declarative_macro( let sp = token.span.substitute_dummy(def.span); let mut err = sess.dcx().struct_span_err(sp, s); err.span_label(sp, msg); - annotate_doc_comment(sess.dcx(), &mut err, sess.source_map(), sp); + annotate_doc_comment(&mut err, sess.source_map(), sp); let guar = err.emit(); return dummy_syn_ext(guar); } diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index 3295a91029ea..25958e03028f 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -42,7 +42,7 @@ impl MetaVarExpr { let ident = parse_ident(&mut tts, psess, outer_span)?; let Some(TokenTree::Delimited(.., Delimiter::Parenthesis, args)) = tts.next() else { let msg = "meta-variable expression parameter must be wrapped in parentheses"; - return Err(psess.dcx.struct_span_err(ident.span, msg)); + return Err(psess.dcx().struct_span_err(ident.span, msg)); }; check_trailing_token(&mut tts, psess)?; let mut iter = args.trees(); @@ -62,12 +62,12 @@ impl MetaVarExpr { break; } if !try_eat_comma(&mut iter) { - return Err(psess.dcx.struct_span_err(outer_span, "expected comma")); + return Err(psess.dcx().struct_span_err(outer_span, "expected comma")); } } if result.len() < 2 { return Err(psess - .dcx + .dcx() .struct_span_err(ident.span, "`concat` must have at least two elements")); } MetaVarExpr::Concat(result.into()) @@ -81,7 +81,7 @@ impl MetaVarExpr { "len" => MetaVarExpr::Len(parse_depth(&mut iter, psess, ident.span)?), _ => { let err_msg = "unrecognized meta-variable expression"; - let mut err = psess.dcx.struct_span_err(ident.span, err_msg); + let mut err = psess.dcx().struct_span_err(ident.span, err_msg); err.span_suggestion( ident.span, "supported expressions are count, ignore, index and len", @@ -120,7 +120,7 @@ fn check_trailing_token<'psess>( ) -> PResult<'psess, ()> { if let Some(tt) = iter.next() { let mut diag = psess - .dcx + .dcx() .struct_span_err(tt.span(), format!("unexpected token: {}", pprust::tt_to_string(tt))); diag.span_note(tt.span(), "meta-variable expression must not have trailing tokens"); Err(diag) @@ -139,7 +139,7 @@ fn parse_count<'psess>( let ident = parse_ident(iter, psess, span)?; let depth = if try_eat_comma(iter) { if iter.look_ahead(0).is_none() { - return Err(psess.dcx.struct_span_err( + return Err(psess.dcx().struct_span_err( span, "`count` followed by a comma must have an associated index indicating its depth", )); @@ -160,7 +160,7 @@ fn parse_depth<'psess>( let Some(tt) = iter.next() else { return Ok(0) }; let TokenTree::Token(token::Token { kind: token::TokenKind::Literal(lit), .. }, _) = tt else { return Err(psess - .dcx + .dcx() .struct_span_err(span, "meta-variable expression depth must be a literal")); }; if let Ok(lit_kind) = LitKind::from_token_lit(*lit) @@ -170,7 +170,7 @@ fn parse_depth<'psess>( Ok(n_usize) } else { let msg = "only unsuffixes integer literals are supported in meta-variable expressions"; - Err(psess.dcx.struct_span_err(span, msg)) + Err(psess.dcx().struct_span_err(span, msg)) } } @@ -181,20 +181,21 @@ fn parse_ident<'psess>( fallback_span: Span, ) -> PResult<'psess, Ident> { let Some(tt) = iter.next() else { - return Err(psess.dcx.struct_span_err(fallback_span, "expected identifier")); + return Err(psess.dcx().struct_span_err(fallback_span, "expected identifier")); }; let TokenTree::Token(token, _) = tt else { - return Err(psess.dcx.struct_span_err(tt.span(), "expected identifier")); + return Err(psess.dcx().struct_span_err(tt.span(), "expected identifier")); }; if let Some((elem, is_raw)) = token.ident() { if let IdentIsRaw::Yes = is_raw { - return Err(psess.dcx.struct_span_err(elem.span, RAW_IDENT_ERR)); + return Err(psess.dcx().struct_span_err(elem.span, RAW_IDENT_ERR)); } return Ok(elem); } let token_str = pprust::token_to_string(token); - let mut err = - psess.dcx.struct_span_err(token.span, format!("expected identifier, found `{token_str}`")); + let mut err = psess + .dcx() + .struct_span_err(token.span, format!("expected identifier, found `{token_str}`")); err.span_suggestion( token.span, format!("try removing `{token_str}`"), @@ -236,7 +237,7 @@ fn eat_dollar<'psess>( let _ = iter.next(); return Ok(()); } - Err(psess.dcx.struct_span_err( + Err(psess.dcx().struct_span_err( span, "meta-variables within meta-variable expressions must be referenced using a dollar sign", )) diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 914bd03675a7..f935f1b77e0b 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -10,7 +10,7 @@ use rustc_ast::token::IdentIsRaw; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{pluralize, Diag, DiagCtxt, PResult}; +use rustc_errors::{pluralize, Diag, DiagCtxtHandle, PResult}; use rustc_parse::parser::ParseNtResult; use rustc_session::parse::ParseSess; use rustc_span::hygiene::{LocalExpnId, Transparency}; @@ -141,7 +141,7 @@ pub(super) fn transcribe<'a>( let mut result_stack = Vec::new(); let mut marker = Marker(expand_id, transparency, Default::default()); - let dcx = &psess.dcx; + let dcx = psess.dcx(); loop { // Look at the last frame on the stack. // If it still has a TokenTree we have not looked at yet, use that tree. @@ -571,7 +571,7 @@ fn lockstep_iter_size( /// * `[ $( ${count(foo, 1)} ),* ]` will return an error because `${count(foo, 1)}` is /// declared inside a single repetition and the index `1` implies two nested repetitions. fn count_repetitions<'a>( - dcx: &'a DiagCtxt, + dcx: DiagCtxtHandle<'a>, depth_user: usize, mut matched: &NamedMatch, repeats: &[(usize, usize)], @@ -632,7 +632,7 @@ fn count_repetitions<'a>( /// Returns a `NamedMatch` item declared on the LHS given an arbitrary [Ident] fn matched_from_ident<'ctx, 'interp, 'rslt>( - dcx: &'ctx DiagCtxt, + dcx: DiagCtxtHandle<'ctx>, ident: Ident, interp: &'interp FxHashMap, ) -> PResult<'ctx, &'rslt NamedMatch> @@ -646,7 +646,7 @@ where /// Used by meta-variable expressions when an user input is out of the actual declared bounds. For /// example, index(999999) in an repetition of only three elements. -fn out_of_bounds_err<'a>(dcx: &'a DiagCtxt, max: usize, span: Span, ty: &str) -> Diag<'a> { +fn out_of_bounds_err<'a>(dcx: DiagCtxtHandle<'a>, max: usize, span: Span, ty: &str) -> Diag<'a> { let msg = if max == 0 { format!( "meta-variable expression `{ty}` with depth parameter \ @@ -662,7 +662,7 @@ fn out_of_bounds_err<'a>(dcx: &'a DiagCtxt, max: usize, span: Span, ty: &str) -> } fn transcribe_metavar_expr<'a>( - dcx: &'a DiagCtxt, + dcx: DiagCtxtHandle<'a>, expr: &MetaVarExpr, interp: &FxHashMap, marker: &mut Marker, @@ -730,7 +730,7 @@ fn transcribe_metavar_expr<'a>( /// Extracts an identifier that can be originated from a `$var:ident` variable or from a token tree. fn extract_ident<'a>( - dcx: &'a DiagCtxt, + dcx: DiagCtxtHandle<'a>, ident: Ident, interp: &FxHashMap, ) -> PResult<'a, String> { diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 93f8682090d7..5508358f53bb 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -522,7 +522,7 @@ impl server::FreeFunctions for Rustc<'_, '_> { fn emit_diagnostic(&mut self, diagnostic: Diagnostic) { let message = rustc_errors::DiagMessage::from(diagnostic.message); let mut diag: Diag<'_, ()> = - Diag::new(&self.psess().dcx, diagnostic.level.to_internal(), message); + Diag::new(self.psess().dcx(), diagnostic.level.to_internal(), message); diag.span(MultiSpan::from_spans(diagnostic.spans)); for child in diagnostic.children { // This message comes from another diagnostic, and we are just reconstructing the diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 58832cb10875..066a5a8f046e 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -567,8 +567,8 @@ declare_features! ( (unstable, optimize_attribute, "1.34.0", Some(54882)), /// Allows postfix match `expr.match { ... }` (unstable, postfix_match, "1.79.0", Some(121618)), - /// Allows `use<'a, 'b, A, B>` in `impl use<...> Trait` for precise capture of generic args. - (incomplete, precise_capturing, "1.79.0", Some(123432)), + /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args. + (unstable, precise_capturing, "1.79.0", Some(123432)), /// Allows macro attributes on expressions, statements and non-inline modules. (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d4a22c4c31f6..22a6c06bba32 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -463,6 +463,7 @@ pub enum TraitBoundModifier { pub enum GenericBound<'hir> { Trait(PolyTraitRef<'hir>, TraitBoundModifier), Outlives(&'hir Lifetime), + Use(&'hir [PreciseCapturingArg<'hir>], Span), } impl GenericBound<'_> { @@ -477,6 +478,7 @@ impl GenericBound<'_> { match self { GenericBound::Trait(t, ..) => t.span, GenericBound::Outlives(l) => l.ident.span, + GenericBound::Use(_, span) => *span, } } } @@ -2689,8 +2691,6 @@ pub struct OpaqueTy<'hir> { /// originating from a trait method. This makes it so that the opaque is /// lowered as an associated type. pub in_trait: bool, - /// List of arguments captured via `impl use<'a, P, ...> Trait` syntax. - pub precise_capturing_args: Option<(&'hir [PreciseCapturingArg<'hir>], Span)>, } #[derive(Debug, Clone, Copy, HashStable_Generic)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 5a16f266dab3..065ecc5d7b7b 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -532,15 +532,10 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_ty(ty)); try_visit!(visitor.visit_generics(generics)); } - ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, precise_capturing_args, .. }) => { + ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, .. }) => { try_visit!(visitor.visit_id(item.hir_id())); try_visit!(walk_generics(visitor, generics)); walk_list!(visitor, visit_param_bound, bounds); - if let Some((precise_capturing_args, _)) = precise_capturing_args { - for arg in precise_capturing_args { - try_visit!(visitor.visit_precise_capturing_arg(arg)); - } - } } ItemKind::Enum(ref enum_definition, ref generics) => { try_visit!(visitor.visit_generics(generics)); @@ -1147,6 +1142,10 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>( match *bound { GenericBound::Trait(ref typ, _modifier) => visitor.visit_poly_trait_ref(typ), GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime), + GenericBound::Use(args, _) => { + walk_list!(visitor, visit_precise_capturing_arg, args); + V::Result::output() + } } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 72e5995e892e..3b53c253195f 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -481,9 +481,12 @@ fn sanity_check_found_hidden_type<'tcx>( /// 2. Checking that all lifetimes that are implicitly captured are mentioned. /// 3. Asserting that all parameters mentioned in the captures list are invariant. fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) { - let hir::OpaqueTy { precise_capturing_args, .. } = + let hir::OpaqueTy { bounds, .. } = *tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); - let Some((precise_capturing_args, _)) = precise_capturing_args else { + let Some(precise_capturing_args) = bounds.iter().find_map(|bound| match *bound { + hir::GenericBound::Use(bounds, ..) => Some(bounds), + _ => None, + }) else { // No precise capturing args; nothing to validate return; }; diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs index 2cdcc06f53c0..17cb20df7546 100644 --- a/compiler/rustc_hir_analysis/src/check/errs.rs +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -63,7 +63,7 @@ fn handle_static_mut_ref( } else { (errors::StaticMutRefSugg::Shared { span, var }, "shared") }; - tcx.sess.psess.dcx.emit_err(errors::StaticMutRef { span, sugg, shared }); + tcx.dcx().emit_err(errors::StaticMutRef { span, sugg, shared }); } else { let (sugg, shared) = if mutable == Mutability::Mut { (errors::RefOfMutStaticSugg::Mut { span, var }, "mutable") diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 61ac4af01519..9421269e51ea 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -403,74 +403,56 @@ fn emit_orphan_check_error<'tcx>( match *ty.kind() { ty::Slice(_) => { if is_foreign { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsForeign { span }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span }); } else { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsName { span, name: "slices" }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsName { + span, + name: "slices", + }); } } ty::Array(..) => { if is_foreign { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsForeign { span }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span }); } else { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsName { span, name: "arrays" }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsName { + span, + name: "arrays", + }); } } ty::Tuple(..) => { if is_foreign { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsForeign { span }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span }); } else { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsName { span, name: "tuples" }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsName { + span, + name: "tuples", + }); } } ty::Alias(ty::Opaque, ..) => { - diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsOpaque { span }); + diag.subdiagnostic(errors::OnlyCurrentTraitsOpaque { span }); } ty::RawPtr(ptr_ty, mutbl) => { if !trait_ref.self_ty().has_param() { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsPointerSugg { - wrapper_span: impl_.self_ty.span, - struct_span: item.span.shrink_to_lo(), - mut_key: mutbl.prefix_str(), - ptr_ty, - }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsPointerSugg { + wrapper_span: impl_.self_ty.span, + struct_span: item.span.shrink_to_lo(), + mut_key: mutbl.prefix_str(), + ptr_ty, + }); } - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsPointer { span, pointer: ty }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsPointer { span, pointer: ty }); } ty::Adt(adt_def, _) => { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsAdt { - span, - name: tcx.def_path_str(adt_def.did()), - }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsAdt { + span, + name: tcx.def_path_str(adt_def.did()), + }); } _ => { - diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsTy { span, ty }); + diag.subdiagnostic(errors::OnlyCurrentTraitsTy { span, ty }); } } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 41dceea2e328..cff8d5a5ea50 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -2,7 +2,7 @@ use crate::fluent_generated as fluent; use rustc_errors::{ - codes::*, Applicability, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, MultiSpan, + codes::*, Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; @@ -424,7 +424,7 @@ pub struct MissingTypeParams { // Manual implementation of `Diagnostic` to be able to call `span_to_snippet`. impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams { #[track_caller] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut err = Diag::new(dcx, level, fluent::hir_analysis_missing_type_params); err.span(self.span); err.code(E0393); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 9a6bc8a7b721..c7699b0b310f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -178,6 +178,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { lifetime.ident.span, ); } + hir::GenericBound::Use(..) => { + // We don't actually lower `use` into the type layer. + } } } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index d32d0183c4e4..b21f1eadfb7a 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -13,7 +13,7 @@ use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_hir as hir; use rustc_hir::{ BindingMode, ByRef, GenericArg, GenericBound, GenericParam, GenericParamKind, HirId, - LifetimeParamKind, Node, PatKind, RangeEnd, Term, TraitBoundModifier, + LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, TraitBoundModifier, }; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, Ident, Symbol}; @@ -2100,10 +2100,24 @@ impl<'a> State<'a> { GenericBound::Outlives(lt) => { self.print_lifetime(lt); } + GenericBound::Use(args, _) => { + self.word("use <"); + + self.commasep(Inconsistent, args, |s, arg| s.print_precise_capturing_arg(*arg)); + + self.word(">"); + } } } } + fn print_precise_capturing_arg(&mut self, arg: PreciseCapturingArg<'_>) { + match arg { + PreciseCapturingArg::Lifetime(lt) => self.print_lifetime(lt), + PreciseCapturingArg::Param(arg) => self.print_ident(arg.ident), + } + } + fn print_generic_params(&mut self, generic_params: &[GenericParam<'_>]) { if !generic_params.is_empty() { self.word("<"); diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 281af80bff57..4e2104ff5615 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -246,7 +246,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let semi = expr.span.shrink_to_hi().with_hi(semi_span.hi()); let sugg = crate::errors::RemoveSemiForCoerce { expr: expr.span, ret, semi }; - diag.subdiagnostic(self.dcx(), sugg); + diag.subdiagnostic(sugg); } /// When the previously checked expression (the scrutinee) diverges, diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 9e9a1f678edd..587085102821 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -1005,25 +1005,19 @@ impl<'a, 'tcx> CastCheck<'tcx> { if let Some((deref_ty, _)) = derefed { // Give a note about what the expr derefs to. if deref_ty != self.expr_ty.peel_refs() { - err.subdiagnostic( - fcx.dcx(), - errors::DerefImplsIsEmpty { - span: self.expr_span, - deref_ty: fcx.ty_to_string(deref_ty), - }, - ); + err.subdiagnostic(errors::DerefImplsIsEmpty { + span: self.expr_span, + deref_ty: fcx.ty_to_string(deref_ty), + }); } // Create a multipart suggestion: add `!` and `.is_empty()` in // place of the cast. - err.subdiagnostic( - fcx.dcx(), - errors::UseIsEmpty { - lo: self.expr_span.shrink_to_lo(), - hi: self.span.with_lo(self.expr_span.hi()), - expr_ty: fcx.ty_to_string(self.expr_ty), - }, - ); + err.subdiagnostic(errors::UseIsEmpty { + lo: self.expr_span.shrink_to_lo(), + hi: self.span.with_lo(self.expr_span.hi()), + expr_ty: fcx.ty_to_string(self.expr_ty), + }); } } } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index fcd22b746769..31f85e21d713 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1782,20 +1782,14 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } let rpid_def_span = fcx.tcx.def_span(rpit_def_id); - err.subdiagnostic( - fcx.tcx.dcx(), - SuggestBoxingForReturnImplTrait::ChangeReturnType { - start_sp: rpid_def_span.with_hi(rpid_def_span.lo() + BytePos(4)), - end_sp: rpid_def_span.shrink_to_hi(), - }, - ); + err.subdiagnostic(SuggestBoxingForReturnImplTrait::ChangeReturnType { + start_sp: rpid_def_span.with_hi(rpid_def_span.lo() + BytePos(4)), + end_sp: rpid_def_span.shrink_to_hi(), + }); let (starts, ends) = arm_spans.map(|span| (span.shrink_to_lo(), span.shrink_to_hi())).unzip(); - err.subdiagnostic( - fcx.tcx.dcx(), - SuggestBoxingForReturnImplTrait::BoxReturnExpr { starts, ends }, - ); + err.subdiagnostic(SuggestBoxingForReturnImplTrait::BoxReturnExpr { starts, ends }); } fn report_return_mismatched_types<'a>( diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index fe497498c4bc..233dc2afa9b2 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -384,7 +384,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(sp) = tcx.sess.psess.ambiguous_block_expr_parse.borrow().get(&sp) { - err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp)); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } oprnd_t = Ty::new_error(tcx, err.emit()); } @@ -2018,10 +2018,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .shrink_to_hi() .to(range_end.span); - err.subdiagnostic( - self.dcx(), - TypeMismatchFruTypo { expr_span: range_start.span, fru_span, expr }, - ); + err.subdiagnostic(TypeMismatchFruTypo { expr_span: range_start.span, fru_span, expr }); // Suppress any range expr type mismatches self.dcx().try_steal_replace_and_emit_err( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 10d9e07db6f1..1138642c56d6 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1435,7 +1435,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // The user provided `ptr::null()`, but the function expects // `ptr::null_mut()`. - err.subdiagnostic(self.dcx(), SuggestPtrNullMut { span: arg.span }); + err.subdiagnostic(SuggestPtrNullMut { span: arg.span }); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 2ef27e6a0ba7..1713d75092e2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -5,14 +5,13 @@ mod checks; mod inspect_obligations; mod suggestions; -use rustc_errors::ErrorGuaranteed; +use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed}; use crate::coercion::DynamicCoerceMany; use crate::fallback::DivergingFallbackBehavior; use crate::fn_ctxt::checks::DivergingBlockBehavior; use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt}; use hir::def_id::CRATE_DEF_ID; -use rustc_errors::DiagCtxt; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; @@ -145,8 +144,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(crate) fn dcx(&self) -> &'tcx DiagCtxt { - self.tcx.dcx() + pub(crate) fn dcx(&self) -> DiagCtxtHandle<'tcx> { + self.infcx.dcx() } pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 9743dc7c69fb..337a92c0d012 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -460,16 +460,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // but those checks need to be a bit more delicate and the benefit is diminishing. if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref { let sugg = prefix_wrap(".as_ref()"); - err.subdiagnostic( - self.dcx(), - errors::SuggestConvertViaMethod { - span: expr.span.shrink_to_hi(), - sugg, - expected, - found, - borrow_removal_span, - }, - ); + err.subdiagnostic(errors::SuggestConvertViaMethod { + span: expr.span.shrink_to_hi(), + sugg, + expected, + found, + borrow_removal_span, + }); return true; } else if let Some((deref_ty, _)) = self.autoderef(expr.span, found_ty_inner).silence_errors().nth(1) @@ -477,16 +474,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && error_tys_equate_as_ref { let sugg = prefix_wrap(".as_deref()"); - err.subdiagnostic( - self.dcx(), - errors::SuggestConvertViaMethod { - span: expr.span.shrink_to_hi(), - sugg, - expected, - found, - borrow_removal_span, - }, - ); + err.subdiagnostic(errors::SuggestConvertViaMethod { + span: expr.span.shrink_to_hi(), + sugg, + expected, + found, + borrow_removal_span, + }); return true; } else if let ty::Adt(adt, _) = found_ty_inner.peel_refs().kind() && self.tcx.is_lang_item(adt.did(), LangItem::String) @@ -573,7 +567,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { end: span.shrink_to_hi(), }, }; - err.subdiagnostic(self.dcx(), suggest_boxing); + err.subdiagnostic(suggest_boxing); true } else { @@ -814,28 +808,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match &fn_decl.output { &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() && !can_suggest => { // `fn main()` must return `()`, do not suggest changing return type - err.subdiagnostic(self.dcx(), errors::ExpectedReturnTypeLabel::Unit { span }); + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span }); return true; } &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => { if let Some(found) = found.make_suggestable(self.tcx, false, None) { - err.subdiagnostic( - self.dcx(), - errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() }, - ); + err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { + span, + found: found.to_string(), + }); return true; } else if let Some(sugg) = suggest_impl_trait(self, self.param_env, found) { - err.subdiagnostic( - self.dcx(), - errors::AddReturnTypeSuggestion::Add { span, found: sugg }, - ); + err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: sugg }); return true; } else { // FIXME: if `found` could be `impl Iterator` we should suggest that. - err.subdiagnostic( - self.dcx(), - errors::AddReturnTypeSuggestion::MissingHere { span }, - ); + err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span }); return true; } } @@ -856,19 +844,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?found); if found.is_suggestable(self.tcx, false) { if ty.span.is_empty() { - err.subdiagnostic( - self.dcx(), - errors::AddReturnTypeSuggestion::Add { - span: ty.span, - found: found.to_string(), - }, - ); + err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { + span: ty.span, + found: found.to_string(), + }); return true; } else { - err.subdiagnostic( - self.dcx(), - errors::ExpectedReturnTypeLabel::Other { span: ty.span, expected }, - ); + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { + span: ty.span, + expected, + }); } } } else { @@ -883,10 +868,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.normalize(hir_ty.span, ty); let ty = self.tcx.instantiate_bound_regions_with_erased(ty); if self.can_coerce(expected, ty) { - err.subdiagnostic( - self.dcx(), - errors::ExpectedReturnTypeLabel::Other { span: hir_ty.span, expected }, - ); + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { + span: hir_ty.span, + expected, + }); self.try_suggest_return_impl_trait(err, expected, found, fn_id); self.note_caller_chooses_ty_for_ty_param(err, expected, found); return true; @@ -905,13 +890,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { found: Ty<'tcx>, ) { if let ty::Param(expected_ty_as_param) = expected.kind() { - diag.subdiagnostic( - self.dcx(), - errors::NoteCallerChoosesTyForTyParam { - ty_param_name: expected_ty_as_param.name, - found_ty: found, - }, - ); + diag.subdiagnostic(errors::NoteCallerChoosesTyForTyParam { + ty_param_name: expected_ty_as_param.name, + found_ty: found, + }); } } @@ -1136,7 +1118,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sp = self.tcx.sess.source_map().start_point(expr.span).with_parent(None); if let Some(sp) = self.tcx.sess.psess.ambiguous_block_expr_parse.borrow().get(&sp) { // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }` - err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp)); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); true } else { false @@ -1250,7 +1232,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { return false; }; - diag.subdiagnostic(self.dcx(), subdiag); + diag.subdiagnostic(subdiag); return true; } } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index abbfe452f5f3..ff066bb9edeb 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2788,32 +2788,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { errors: Vec>, suggest_derive: bool, ) { - let all_local_types_needing_impls = - errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { - match pred.self_ty().kind() { - ty::Adt(def, _) => def.did().is_local(), - _ => false, - } - } - _ => false, - }); - let mut preds: Vec<_> = errors + let preds: Vec<_> = errors .iter() .filter_map(|e| match e.obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => Some(pred), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { + match pred.self_ty().kind() { + ty::Adt(_, _) => Some(pred), + _ => None, + } + } _ => None, }) .collect(); - preds.sort_by_key(|pred| pred.trait_ref.to_string()); - let def_ids = preds + + // Note for local items and foreign items respectively. + let (mut local_preds, mut foreign_preds): (Vec<_>, Vec<_>) = + preds.iter().partition(|&pred| { + if let ty::Adt(def, _) = pred.self_ty().kind() { + def.did().is_local() + } else { + false + } + }); + + local_preds.sort_by_key(|pred: &&ty::TraitPredicate<'_>| pred.trait_ref.to_string()); + let local_def_ids = local_preds .iter() .filter_map(|pred| match pred.self_ty().kind() { ty::Adt(def, _) => Some(def.did()), _ => None, }) .collect::>(); - let mut spans: MultiSpan = def_ids + let mut local_spans: MultiSpan = local_def_ids .iter() .filter_map(|def_id| { let span = self.tcx.def_span(*def_id); @@ -2821,11 +2827,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .collect::>() .into(); - - for pred in &preds { + for pred in &local_preds { match pred.self_ty().kind() { - ty::Adt(def, _) if def.did().is_local() => { - spans.push_span_label( + ty::Adt(def, _) => { + local_spans.push_span_label( self.tcx.def_span(def.did()), format!("must implement `{}`", pred.trait_ref.print_trait_sugared()), ); @@ -2833,24 +2838,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } } - - if all_local_types_needing_impls && spans.primary_span().is_some() { - let msg = if preds.len() == 1 { + if local_spans.primary_span().is_some() { + let msg = if local_preds.len() == 1 { format!( "an implementation of `{}` might be missing for `{}`", - preds[0].trait_ref.print_trait_sugared(), - preds[0].self_ty() + local_preds[0].trait_ref.print_trait_sugared(), + local_preds[0].self_ty() ) } else { format!( "the following type{} would have to `impl` {} required trait{} for this \ operation to be valid", - pluralize!(def_ids.len()), - if def_ids.len() == 1 { "its" } else { "their" }, - pluralize!(preds.len()), + pluralize!(local_def_ids.len()), + if local_def_ids.len() == 1 { "its" } else { "their" }, + pluralize!(local_preds.len()), ) }; - err.span_note(spans, msg); + err.span_note(local_spans, msg); + } + + foreign_preds.sort_by_key(|pred: &&ty::TraitPredicate<'_>| pred.trait_ref.to_string()); + let foreign_def_ids = foreign_preds + .iter() + .filter_map(|pred| match pred.self_ty().kind() { + ty::Adt(def, _) => Some(def.did()), + _ => None, + }) + .collect::>(); + let mut foreign_spans: MultiSpan = foreign_def_ids + .iter() + .filter_map(|def_id| { + let span = self.tcx.def_span(*def_id); + if span.is_dummy() { None } else { Some(span) } + }) + .collect::>() + .into(); + for pred in &foreign_preds { + match pred.self_ty().kind() { + ty::Adt(def, _) => { + foreign_spans.push_span_label( + self.tcx.def_span(def.did()), + format!("not implement `{}`", pred.trait_ref.print_trait_sugared()), + ); + } + _ => {} + } + } + if foreign_spans.primary_span().is_some() { + let msg = if foreign_preds.len() == 1 { + format!( + "the foreign item type `{}` doesn't implement `{}`", + foreign_preds[0].self_ty(), + foreign_preds[0].trait_ref.print_trait_sugared() + ) + } else { + format!( + "the foreign item type{} {} implement required trait{} for this \ + operation to be valid", + pluralize!(foreign_def_ids.len()), + if foreign_def_ids.len() > 1 { "don't" } else { "doesn't" }, + pluralize!(foreign_preds.len()), + ) + }; + err.span_note(foreign_spans, msg); } let preds: Vec<_> = errors @@ -3729,22 +3779,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if impls_trait(trait_info.def_id) { self.suggest_valid_traits(err, item_name, vec![trait_info.def_id], false); } else { - err.subdiagnostic( - self.dcx(), - CandidateTraitNote { - span: self.tcx.def_span(trait_info.def_id), - trait_name: self.tcx.def_path_str(trait_info.def_id), - item_name, - action_or_ty: if trait_missing_method { - "NONE".to_string() - } else { - param_type.map_or_else( - || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented. - |p| p.to_string(), - ) - }, + err.subdiagnostic(CandidateTraitNote { + span: self.tcx.def_span(trait_info.def_id), + trait_name: self.tcx.def_path_str(trait_info.def_id), + item_name, + action_or_ty: if trait_missing_method { + "NONE".to_string() + } else { + param_type.map_or_else( + || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented. + |p| p.to_string(), + ) }, - ); + }); } } trait_infos => { diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index d774ae2146aa..5a11cb7096f3 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -820,7 +820,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the previous expression was a block expression, suggest parentheses // (turning this into a binary subtraction operation instead.) // for example, `{2} - 2` -> `({2}) - 2` (see src\test\ui\parser\expr-as-stmt.rs) - err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp)); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } else { match actual.kind() { Uint(_) if op == hir::UnOp::Neg => { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index e15866f3f0f6..227691d09943 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -61,8 +61,8 @@ use crate::traits::{ use crate::infer::relate::{self, RelateResult, TypeRelation}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ - codes::*, pluralize, struct_span_code_err, Applicability, Diag, DiagCtxt, DiagStyledString, - ErrorGuaranteed, IntoDiagArg, StringPart, + codes::*, pluralize, struct_span_code_err, Applicability, Diag, DiagCtxtHandle, + DiagStyledString, ErrorGuaranteed, IntoDiagArg, StringPart, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -139,8 +139,8 @@ pub struct TypeErrCtxt<'a, 'tcx> { } impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { - pub fn dcx(&self) -> &'tcx DiagCtxt { - self.infcx.tcx.dcx() + pub fn dcx(&self) -> DiagCtxtHandle<'tcx> { + self.infcx.dcx() } /// This is just to avoid a potential footgun of accidentally @@ -892,7 +892,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { arm_ty, arm_span, ) { - err.subdiagnostic(self.dcx(), subdiag); + err.subdiagnostic(subdiag); } } }, @@ -918,7 +918,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { else_ty, else_span, ) { - err.subdiagnostic(self.dcx(), subdiag); + err.subdiagnostic(subdiag); } } ObligationCauseCode::LetElse => { diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index acb74f8a82ce..8fd19563c305 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -369,7 +369,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { trait_predicates: trait_predicates.join(", "), } }; - err.subdiagnostic(self.dcx(), suggestion); + err.subdiagnostic(suggestion); } pub(super) fn report_placeholder_failure( diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 17fb760295ae..74c65e93616e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -121,7 +121,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span_low: cause.span.shrink_to_lo(), span_high: cause.span.shrink_to_hi(), }; - diag.subdiagnostic(self.dcx(), sugg); + diag.subdiagnostic(sugg); } _ => { // More than one matching variant. @@ -130,7 +130,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { cause_span: cause.span, compatible_variants, }; - diag.subdiagnostic(self.dcx(), sugg); + diag.subdiagnostic(sugg); } } } @@ -202,10 +202,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }, (_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => { // FIXME: Seems like we can't have a suggestion and a note with different spans in a single subdiagnostic - diag.subdiagnostic( - self.dcx(), - ConsiderAddingAwait::FutureSugg { span: exp_span.shrink_to_hi() }, - ); + diag.subdiagnostic(ConsiderAddingAwait::FutureSugg { + span: exp_span.shrink_to_hi(), + }); Some(ConsiderAddingAwait::FutureSuggNote { span: exp_span }) } (Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code() @@ -233,7 +232,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { _ => None, }; if let Some(subdiag) = subdiag { - diag.subdiagnostic(self.dcx(), subdiag); + diag.subdiagnostic(subdiag); } } @@ -269,7 +268,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } else { return; }; - diag.subdiagnostic(self.dcx(), suggestion); + diag.subdiagnostic(suggestion); } } } @@ -401,15 +400,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (true, false) => FunctionPointerSuggestion::UseRef { span, fn_name }, (false, true) => FunctionPointerSuggestion::RemoveRef { span, fn_name }, (true, true) => { - diag.subdiagnostic(self.dcx(), FnItemsAreDistinct); + diag.subdiagnostic(FnItemsAreDistinct); FunctionPointerSuggestion::CastRef { span, fn_name, sig: *sig } } (false, false) => { - diag.subdiagnostic(self.dcx(), FnItemsAreDistinct); + diag.subdiagnostic(FnItemsAreDistinct); FunctionPointerSuggestion::Cast { span, fn_name, sig: *sig } } }; - diag.subdiagnostic(self.dcx(), sugg); + diag.subdiagnostic(sugg); } (ty::FnDef(did1, args1), ty::FnDef(did2, args2)) => { let expected_sig = @@ -418,7 +417,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &(self.normalize_fn_sig)(self.tcx.fn_sig(*did2).instantiate(self.tcx, args2)); if self.same_type_modulo_infer(*expected_sig, *found_sig) { - diag.subdiagnostic(self.dcx(), FnUniqTypes); + diag.subdiagnostic(FnUniqTypes); } if !self.same_type_modulo_infer(*found_sig, *expected_sig) @@ -447,7 +446,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } }; - diag.subdiagnostic(self.dcx(), sug); + diag.subdiagnostic(sug); } (ty::FnDef(did, args), ty::FnPtr(sig)) => { let expected_sig = @@ -466,7 +465,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { format!("{fn_name} as {found_sig}") }; - diag.subdiagnostic(self.dcx(), FnConsiderCasting { casting }); + diag.subdiagnostic(FnConsiderCasting { casting }); } _ => { return; @@ -889,7 +888,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let diag = self.consider_returning_binding_diag(blk, expected_ty); match diag { Some(diag) => { - err.subdiagnostic(self.dcx(), diag); + err.subdiagnostic(diag); true } None => false, diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 8412912b9f37..510e9a06dfb0 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -4,13 +4,14 @@ pub use lexical_region_resolve::RegionResolutionError; pub use relate::combine::CombineFields; pub use relate::combine::PredicateEmittingRelation; pub use relate::StructurallyRelateAliases; +use rustc_errors::DiagCtxtHandle; pub use rustc_macros::{TypeFoldable, TypeVisitable}; pub use rustc_middle::ty::IntVarValue; pub use BoundRegionConversionTime::*; pub use RegionVariableOrigin::*; pub use SubregionOrigin::*; -use crate::infer::relate::{Relate, RelateResult}; +use crate::infer::relate::RelateResult; use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine}; use error_reporting::TypeErrCtxt; use free_regions::RegionRelations; @@ -23,7 +24,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::Rollback; use rustc_data_structures::unify as ut; -use rustc_errors::{Diag, DiagCtxt, ErrorGuaranteed}; +use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::extension; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; @@ -44,7 +45,7 @@ use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid}; use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use snapshot::undo_log::InferCtxtUndoLogs; use std::cell::{Cell, RefCell}; use std::fmt; @@ -334,149 +335,6 @@ pub struct InferCtxt<'tcx> { pub obligation_inspector: Cell>>, } -impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { - type Interner = TyCtxt<'tcx>; - - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn universe_of_ty(&self, vid: TyVid) -> Option { - // FIXME(BoxyUwU): this is kind of jank and means that printing unresolved - // ty infers will give you the universe of the var it resolved to not the universe - // it actually had. It also means that if you have a `?0.1` and infer it to `u8` then - // try to print out `?0.1` it will just print `?0`. - match self.probe_ty_var(vid) { - Err(universe) => Some(universe), - Ok(_) => None, - } - } - - fn universe_of_lt(&self, lt: ty::RegionVid) -> Option { - match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) { - Err(universe) => Some(universe), - Ok(_) => None, - } - } - - fn universe_of_ct(&self, ct: ConstVid) -> Option { - // Same issue as with `universe_of_ty` - match self.probe_const_var(ct) { - Err(universe) => Some(universe), - Ok(_) => None, - } - } - - fn root_ty_var(&self, var: TyVid) -> TyVid { - self.root_var(var) - } - - fn root_const_var(&self, var: ConstVid) -> ConstVid { - self.root_const_var(var) - } - - fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> { - match self.probe_ty_var(vid) { - Ok(ty) => ty, - Err(_) => Ty::new_var(self.tcx, self.root_var(vid)), - } - } - - fn opportunistic_resolve_int_var(&self, vid: IntVid) -> Ty<'tcx> { - self.opportunistic_resolve_int_var(vid) - } - - fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> Ty<'tcx> { - self.opportunistic_resolve_float_var(vid) - } - - fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> ty::Const<'tcx> { - match self.probe_const_var(vid) { - Ok(ct) => ct, - Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid)), - } - } - - fn opportunistic_resolve_effect_var(&self, vid: EffectVid) -> ty::Const<'tcx> { - match self.probe_effect_var(vid) { - Some(ct) => ct, - None => { - ty::Const::new_infer(self.tcx, InferConst::EffectVar(self.root_effect_var(vid))) - } - } - } - - fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { - self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) - } - - fn defining_opaque_types(&self) -> &'tcx ty::List { - self.defining_opaque_types - } - - fn next_ty_infer(&self) -> Ty<'tcx> { - self.next_ty_var(DUMMY_SP) - } - - fn next_const_infer(&self) -> ty::Const<'tcx> { - self.next_const_var(DUMMY_SP) - } - - fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> { - self.fresh_args_for_item(DUMMY_SP, def_id) - } - - fn instantiate_binder_with_infer + Copy>( - &self, - value: ty::Binder<'tcx, T>, - ) -> T { - self.instantiate_binder_with_fresh_vars( - DUMMY_SP, - BoundRegionConversionTime::HigherRankedType, - value, - ) - } - - fn enter_forall> + Copy, U>( - &self, - value: ty::Binder<'tcx, T>, - f: impl FnOnce(T) -> U, - ) -> U { - self.enter_forall(value, f) - } - - fn relate>>( - &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - variance: ty::Variance, - rhs: T, - ) -> Result>>, NoSolution> { - self.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs) - } - - fn eq_structurally_relating_aliases>>( - &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - rhs: T, - ) -> Result>>, NoSolution> { - self.at(&ObligationCause::dummy(), param_env) - .eq_structurally_relating_aliases_no_trace(lhs, rhs) - } - - fn resolve_vars_if_possible(&self, value: T) -> T - where - T: TypeFoldable>, - { - self.resolve_vars_if_possible(value) - } - - fn probe(&self, probe: impl FnOnce() -> T) -> T { - self.probe(|_| probe()) - } -} - /// See the `error_reporting` module for more details. #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)] pub enum ValuePairs<'tcx> { @@ -826,10 +684,14 @@ impl<'tcx> InferOk<'tcx, ()> { } impl<'tcx> InferCtxt<'tcx> { - pub fn dcx(&self) -> &'tcx DiagCtxt { + pub fn dcx(&self) -> DiagCtxtHandle<'tcx> { self.tcx.dcx() } + pub fn defining_opaque_types(&self) -> &'tcx ty::List { + self.defining_opaque_types + } + pub fn next_trait_solver(&self) -> bool { self.next_trait_solver } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index c95a10f4e8d2..41c8b941717f 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -9,7 +9,7 @@ use rustc_data_structures::jobserver; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::sync::Lrc; use rustc_errors::registry::Registry; -use rustc_errors::{DiagCtxt, ErrorGuaranteed}; +use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed}; use rustc_lint::LintStore; use rustc_middle::ty; use rustc_middle::ty::CurrentGcx; @@ -46,7 +46,7 @@ pub struct Compiler { } /// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`. -pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec) -> Cfg { +pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec) -> Cfg { cfgs.into_iter() .map(|s| { let psess = ParseSess::with_silent_emitter( @@ -105,7 +105,7 @@ pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec) -> Cfg { } /// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`. -pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec) -> CheckCfg { +pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec) -> CheckCfg { // If any --check-cfg is passed then exhaustive_values and exhaustive_names // are enabled by default. let exhaustive_names = !specs.is_empty(); @@ -451,12 +451,12 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se codegen_backend.init(&sess); - let cfg = parse_cfg(&sess.dcx(), config.crate_cfg); + let cfg = parse_cfg(sess.dcx(), config.crate_cfg); let mut cfg = config::build_configuration(&sess, cfg); util::add_configuration(&mut cfg, &mut sess, &*codegen_backend); sess.psess.config = cfg; - let mut check_cfg = parse_check_cfg(&sess.dcx(), config.crate_check_cfg); + let mut check_cfg = parse_check_cfg(sess.dcx(), config.crate_check_cfg); check_cfg.fill_well_known(&sess.target); sess.psess.check_config = check_cfg; @@ -529,7 +529,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se } pub fn try_print_query_stack( - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, num_frames: Option, file: Option, ) { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 6538995926a5..2909f8adfb0e 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -70,7 +70,7 @@ where Arc::default(), Default::default(), ); - let cfg = parse_cfg(&sess.dcx(), matches.opt_strs("cfg")); + let cfg = parse_cfg(sess.dcx(), matches.opt_strs("cfg")); let cfg = build_configuration(&sess, cfg); f(sess, cfg) }); @@ -761,7 +761,7 @@ fn test_unstable_options_tracking_hash() { }) ); tracked!(codegen_backend, Some("abc".to_string())); - tracked!(coverage_options, CoverageOptions { level: CoverageLevel::Mcdc }); + tracked!(coverage_options, CoverageOptions { level: CoverageLevel::Mcdc, no_mir_spans: true }); tracked!(crate_attr, vec!["abc".to_string()]); tracked!(cross_crate_inline_threshold, InliningThreshold::Always); tracked!(debug_info_for_profiling, true); diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index a311c274a6ba..d4f6d388d9fe 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::{ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{sym, Span}; use crate::fluent_generated as fluent; use crate::{LateContext, LateLintPass}; @@ -53,7 +53,7 @@ declare_lint! { /// while the `impl Display` is live. /// /// To fix this, we can explicitly state that the `impl Display` doesn't - /// capture any lifetimes, using `impl use<> Display`. + /// capture any lifetimes, using `impl Display + use<>`. pub IMPL_TRAIT_OVERCAPTURES, Allow, "`impl Trait` will capture more lifetimes than possibly intended in edition 2024", @@ -79,7 +79,7 @@ declare_lint! { /// # #![feature(precise_capturing, lifetime_capture_rules_2024)] /// # #![allow(incomplete_features)] /// # #![deny(impl_trait_redundant_captures)] - /// fn test<'a>(x: &'a i32) -> impl use<'a> Sized { x } + /// fn test<'a>(x: &'a i32) -> impl Sized + use<'a> { x } /// ``` /// /// {{produces}} @@ -249,7 +249,7 @@ impl<'tcx> TypeVisitor> for VisitOpaqueTypes<'tcx> { // If we have uncaptured args, and if the opaque doesn't already have // `use<>` syntax on it, and we're < edition 2024, then warn the user. if !new_capture_rules - && opaque.precise_capturing_args.is_none() + && !opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..))) && !uncaptured_spans.is_empty() { let suggestion = if let Ok(snippet) = @@ -268,8 +268,8 @@ impl<'tcx> TypeVisitor> for VisitOpaqueTypes<'tcx> { // Make sure that we're not trying to name any APITs if generics.iter().all(|name| !name.starts_with("impl ")) { Some(( - format!(" use<{}>", generics.join(", ")), - opaque_span.with_lo(opaque_span.lo() + BytePos(4)).shrink_to_lo(), + format!(" + use<{}>", generics.join(", ")), + opaque_span.shrink_to_hi(), )) } else { None @@ -294,7 +294,11 @@ impl<'tcx> TypeVisitor> for VisitOpaqueTypes<'tcx> { // have no uncaptured args, then we should warn to the user that // it's redundant to capture all args explicitly. else if new_capture_rules - && let Some((captured_args, capturing_span)) = opaque.precise_capturing_args + && let Some((captured_args, capturing_span)) = + opaque.bounds.iter().find_map(|bound| match *bound { + hir::GenericBound::Use(a, s) => Some((a, s)), + _ => None, + }) { let mut explicitly_captured = UnordSet::default(); for arg in captured_args { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index f60f8f7c6b7f..4ad31ccc280d 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1405,7 +1405,7 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { diag.note(fluent::lint_macro_to_change); } if let Some(cargo_update) = cargo_update { - diag.subdiagnostic(&diag.dcx, cargo_update); + diag.subdiagnostic(cargo_update); } if has_trait { @@ -1471,7 +1471,7 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { diag.note(fluent::lint_non_local_definitions_deprecation); if let Some(cargo_update) = cargo_update { - diag.subdiagnostic(&diag.dcx, cargo_update); + diag.subdiagnostic(cargo_update); } } } @@ -1957,7 +1957,7 @@ impl<'a> LintDiagnostic<'a, ()> for UnusedDef<'_, '_> { diag.note(note.to_string()); } if let Some(sugg) = self.suggestion { - diag.subdiagnostic(diag.dcx, sugg); + diag.subdiagnostic(sugg); } } } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 7a1aa4043be0..195a0f72475f 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1268,7 +1268,7 @@ impl EarlyLintPass for UnusedParens { ast::TyKind::TraitObject(..) => {} ast::TyKind::BareFn(b) if self.with_self_ty_parens && b.generic_params.len() > 0 => {} - ast::TyKind::ImplTrait(_, bounds, _) if bounds.len() > 1 => {} + ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {} _ => { let spans = if !ty.span.from_expansion() { r.span diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index ef6005283d6b..a3abbdcf18ca 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -78,7 +78,7 @@ impl<'a> DiagnosticDerive<'a> { #[track_caller] fn into_diag( self, - dcx: &'_sess rustc_errors::DiagCtxt, + dcx: rustc_errors::DiagCtxtHandle<'_sess>, level: rustc_errors::Level ) -> rustc_errors::Diag<'_sess, G> { #implementation diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 38d4a5ee61ce..46bd80c2df64 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -335,7 +335,7 @@ impl DiagnosticDeriveVariantBuilder { } } (Meta::Path(_), "subdiagnostic") => { - return Ok(quote! { diag.subdiagnostic(diag.dcx, #binding); }); + return Ok(quote! { diag.subdiagnostic(#binding); }); } _ => (), } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index ad283117d7e0..749495bc2ef5 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -10,7 +10,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::owned_slice::OwnedSlice; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard}; -use rustc_errors::DiagCtxt; +use rustc_errors::DiagCtxtHandle; use rustc_expand::base::SyntaxExtension; use rustc_fs_util::try_canonicalize; use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE}; @@ -91,8 +91,8 @@ impl<'a, 'tcx> std::ops::Deref for CrateLoader<'a, 'tcx> { } impl<'a, 'tcx> CrateLoader<'a, 'tcx> { - fn dcx(&self) -> &'tcx DiagCtxt { - &self.tcx.dcx() + fn dcx(&self) -> DiagCtxtHandle<'tcx> { + self.tcx.dcx() } } diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 47d183a04404..b0d82a0e3b7c 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -3,7 +3,7 @@ use std::{ path::{Path, PathBuf}, }; -use rustc_errors::{codes::*, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level}; +use rustc_errors::{codes::*, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{sym, Span, Symbol}; use rustc_target::spec::{PanicStrategy, TargetTriple}; @@ -503,7 +503,7 @@ pub(crate) struct MultipleCandidates { } impl Diagnostic<'_, G> for MultipleCandidates { - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::metadata_multiple_candidates); diag.arg("crate_name", self.crate_name); diag.arg("flavor", self.flavor); @@ -602,7 +602,7 @@ pub struct InvalidMetadataFiles { impl Diagnostic<'_, G> for InvalidMetadataFiles { #[track_caller] - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::metadata_invalid_meta_files); diag.arg("crate_name", self.crate_name); diag.arg("add_info", self.add_info); @@ -631,7 +631,7 @@ pub struct CannotFindCrate { impl Diagnostic<'_, G> for CannotFindCrate { #[track_caller] - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::metadata_cannot_find_crate); diag.arg("crate_name", self.crate_name); diag.arg("current_crate", self.current_crate); diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 3d4e5caa9b27..e3d7dff3c66b 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -111,7 +111,7 @@ macro_rules! arena_types { rustc_middle::ty::EarlyBinder<'tcx, rustc_middle::ty::Ty<'tcx>> >, [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData>, - [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<'tcx>, + [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, [] stripped_cfg_items: rustc_ast::expand::StrippedCfgItem, [] mod_child: rustc_middle::metadata::ModChild, diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index 817ac5946276..fcea1ea81a7c 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -4,10 +4,10 @@ /// /// If you have a span available, you should use [`span_bug`] instead. /// -/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxt::span_delayed_bug`] +/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxtHandle::span_delayed_bug`] /// may be useful. /// -/// [`DiagCtxt::span_delayed_bug`]: rustc_errors::DiagCtxt::span_delayed_bug +/// [`DiagCtxtHandle::span_delayed_bug`]: rustc_errors::DiagCtxtHandle::span_delayed_bug /// [`span_bug`]: crate::span_bug #[macro_export] macro_rules! bug { @@ -30,10 +30,10 @@ macro_rules! bug { /// at the code the compiler was compiling when it ICEd. This is the preferred way to trigger /// ICEs. /// -/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxt::span_delayed_bug`] +/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxtHandle::span_delayed_bug`] /// may be useful. /// -/// [`DiagCtxt::span_delayed_bug`]: rustc_errors::DiagCtxt::span_delayed_bug +/// [`DiagCtxtHandle::span_delayed_bug`]: rustc_errors::DiagCtxtHandle::span_delayed_bug #[macro_export] macro_rules! span_bug { ($span:expr, $msg:expr) => ( diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 8cf1bedf0dae..d1ccd158cf93 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -176,7 +176,7 @@ impl<'a, G: EmissionGuarantee> rustc_errors::LintDiagnostic<'a, G> for Deprecate diag.arg("has_note", false); } if let Some(sub) = self.sub { - diag.subdiagnostic(diag.dcx, sub); + diag.subdiagnostic(sub); } } } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index b0f8a047b82f..2fc466c0e7e9 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -52,7 +52,7 @@ impl AllocBytes for Box<[u8]> { } fn zeroed(size: Size, _align: Align) -> Option { - let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes_usize()).ok()?; + let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes().try_into().ok()?).ok()?; // SAFETY: the box was zero-allocated, which is a valid initial value for Box<[u8]> let bytes = unsafe { bytes.assume_init() }; Some(bytes) @@ -323,7 +323,10 @@ impl Allocation { /// first call this function and then call write_scalar to fill in the right data. pub fn uninit(size: Size, align: Align) -> Self { match Self::uninit_inner(size, align, || { - panic!("Allocation::uninit called with panic_on_fail had allocation failure"); + panic!( + "interpreter ran out of memory: cannot create allocation of {} bytes", + size.bytes() + ); }) { Ok(x) => x, Err(x) => x, diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 9e979620a440..90f80f90767d 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -5,12 +5,12 @@ use rustc_type_ir as ir; pub use rustc_type_ir::solve::*; use crate::ty::{ - self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, + self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, }; mod cache; -pub use cache::{CacheData, EvaluationCache}; +pub use cache::EvaluationCache; pub type Goal<'tcx, P> = ir::solve::Goal, P>; pub type QueryInput<'tcx, P> = ir::solve::QueryInput, P>; @@ -19,17 +19,11 @@ pub type CandidateSource<'tcx> = ir::solve::CandidateSource>; pub type CanonicalInput<'tcx, P = ty::Predicate<'tcx>> = ir::solve::CanonicalInput, P>; pub type CanonicalResponse<'tcx> = ir::solve::CanonicalResponse>; -/// Additional constraints returned on success. -#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)] -pub struct PredefinedOpaquesData<'tcx> { - pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, -} - #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] -pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData<'tcx>>); +pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData>>); impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> { - type Target = PredefinedOpaquesData<'tcx>; + type Target = PredefinedOpaquesData>; fn deref(&self) -> &Self::Target { &self.0 diff --git a/compiler/rustc_middle/src/traits/solve/cache.rs b/compiler/rustc_middle/src/traits/solve/cache.rs index dc31114b2c45..72a8d4eb4050 100644 --- a/compiler/rustc_middle/src/traits/solve/cache.rs +++ b/compiler/rustc_middle/src/traits/solve/cache.rs @@ -5,6 +5,8 @@ use rustc_data_structures::sync::Lock; use rustc_query_system::cache::WithDepNode; use rustc_query_system::dep_graph::DepNodeIndex; use rustc_session::Limit; +use rustc_type_ir::solve::CacheData; + /// The trait solver cache used by `-Znext-solver`. /// /// FIXME(@lcnr): link to some official documentation of how @@ -14,17 +16,9 @@ pub struct EvaluationCache<'tcx> { map: Lock, CacheEntry<'tcx>>>, } -#[derive(Debug, PartialEq, Eq)] -pub struct CacheData<'tcx> { - pub result: QueryResult<'tcx>, - pub proof_tree: Option<&'tcx inspect::CanonicalGoalEvaluationStep>>, - pub additional_depth: usize, - pub encountered_overflow: bool, -} - -impl<'tcx> EvaluationCache<'tcx> { +impl<'tcx> rustc_type_ir::inherent::EvaluationCache> for &'tcx EvaluationCache<'tcx> { /// Insert a final result into the global cache. - pub fn insert( + fn insert( &self, tcx: TyCtxt<'tcx>, key: CanonicalInput<'tcx>, @@ -48,7 +42,7 @@ impl<'tcx> EvaluationCache<'tcx> { if cfg!(debug_assertions) { drop(map); let expected = CacheData { result, proof_tree, additional_depth, encountered_overflow }; - let actual = self.get(tcx, key, [], Limit(additional_depth)); + let actual = self.get(tcx, key, [], additional_depth); if !actual.as_ref().is_some_and(|actual| expected == *actual) { bug!("failed to lookup inserted element for {key:?}: {expected:?} != {actual:?}"); } @@ -59,13 +53,13 @@ impl<'tcx> EvaluationCache<'tcx> { /// and handling root goals of coinductive cycles. /// /// If this returns `Some` the cache result can be used. - pub fn get( + fn get( &self, tcx: TyCtxt<'tcx>, key: CanonicalInput<'tcx>, stack_entries: impl IntoIterator>, - available_depth: Limit, - ) -> Option> { + available_depth: usize, + ) -> Option>> { let map = self.map.borrow(); let entry = map.get(&key)?; @@ -76,7 +70,7 @@ impl<'tcx> EvaluationCache<'tcx> { } if let Some(ref success) = entry.success { - if available_depth.value_within_limit(success.additional_depth) { + if Limit(available_depth).value_within_limit(success.additional_depth) { let QueryData { result, proof_tree } = success.data.get(tcx); return Some(CacheData { result, @@ -87,12 +81,12 @@ impl<'tcx> EvaluationCache<'tcx> { } } - entry.with_overflow.get(&available_depth.0).map(|e| { + entry.with_overflow.get(&available_depth).map(|e| { let QueryData { result, proof_tree } = e.get(tcx); CacheData { result, proof_tree, - additional_depth: available_depth.0, + additional_depth: available_depth, encountered_overflow: true, } }) diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 684b3233cfd6..8e221cdc603b 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -205,6 +205,14 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { self.did() } + fn is_struct(self) -> bool { + self.is_struct() + } + + fn struct_tail_ty(self, interner: TyCtxt<'tcx>) -> Option>> { + Some(interner.type_of(self.non_enum_variant().tail_opt()?.did)) + } + fn is_phantom_data(self) -> bool { self.is_phantom_data() } @@ -212,7 +220,7 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { fn all_field_tys( self, tcx: TyCtxt<'tcx>, - ) -> ty::EarlyBinder<'tcx, impl Iterator>> { + ) -> ty::EarlyBinder<'tcx, impl IntoIterator>> { ty::EarlyBinder::bind( self.all_fields().map(move |field| tcx.type_of(field.did).skip_binder()), ) diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 12f0c38b054a..32d01d07c17e 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -16,8 +16,8 @@ mod valtree; pub use int::*; pub use kind::*; -use rustc_span::Span; use rustc_span::DUMMY_SP; +use rustc_span::{ErrorGuaranteed, Span}; pub use valtree::*; pub type ConstKind<'tcx> = ir::ConstKind>; @@ -176,6 +176,10 @@ impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> { fn new_expr(interner: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Self { Const::new_expr(interner, expr) } + + fn new_error(interner: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self { + Const::new_error(interner, guar) + } } impl<'tcx> Const<'tcx> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e2f15dac0198..6d64c1d50aea 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -47,7 +47,9 @@ use rustc_data_structures::sync::{self, FreezeReadGuard, Lock, Lrc, RwLock, Work #[cfg(parallel_compiler)] use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{Applicability, Diag, DiagCtxt, ErrorGuaranteed, LintDiagnostic, MultiSpan}; +use rustc_errors::{ + Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan, +}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; @@ -71,6 +73,7 @@ use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx} use rustc_target::spec::abi; use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::lang_items::TraitSolverLangItem; +use rustc_type_ir::solve::SolverMode; use rustc_type_ir::TyKind::*; use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo}; use tracing::{debug, instrument}; @@ -89,46 +92,65 @@ use std::ops::{Bound, Deref}; impl<'tcx> Interner for TyCtxt<'tcx> { type DefId = DefId; type LocalDefId = LocalDefId; - type AdtDef = ty::AdtDef<'tcx>; - type GenericArgs = ty::GenericArgsRef<'tcx>; + type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>]; type GenericArg = ty::GenericArg<'tcx>; type Term = ty::Term<'tcx>; - type BoundVarKinds = &'tcx List; - type BoundVarKind = ty::BoundVariableKind; - type CanonicalVars = CanonicalVarInfos<'tcx>; + type BoundVarKind = ty::BoundVariableKind; type PredefinedOpaques = solve::PredefinedOpaques<'tcx>; + + fn mk_predefined_opaques_in_body( + self, + data: PredefinedOpaquesData, + ) -> Self::PredefinedOpaques { + self.mk_predefined_opaques_in_body(data) + } type DefiningOpaqueTypes = &'tcx ty::List; - type ExternalConstraints = ExternalConstraints<'tcx>; type CanonicalGoalEvaluationStepRef = &'tcx solve::inspect::CanonicalGoalEvaluationStep>; + type CanonicalVars = CanonicalVarInfos<'tcx>; + fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars { + self.mk_canonical_var_infos(infos) + } + type ExternalConstraints = ExternalConstraints<'tcx>; + fn mk_external_constraints( + self, + data: ExternalConstraintsData, + ) -> ExternalConstraints<'tcx> { + self.mk_external_constraints(data) + } + type DepNodeIndex = DepNodeIndex; + fn with_cached_task(self, task: impl FnOnce() -> T) -> (T, DepNodeIndex) { + self.dep_graph.with_anon_task(self, crate::dep_graph::dep_kinds::TraitSelect, task) + } type Ty = Ty<'tcx>; type Tys = &'tcx List>; + type FnInputTys = &'tcx [Ty<'tcx>]; type ParamTy = ParamTy; type BoundTy = ty::BoundTy; - type PlaceholderTy = ty::PlaceholderType; + type PlaceholderTy = ty::PlaceholderType; type ErrorGuaranteed = ErrorGuaranteed; type BoundExistentialPredicates = &'tcx List>; - type AllocId = crate::mir::interpret::AllocId; + type AllocId = crate::mir::interpret::AllocId; type Pat = Pattern<'tcx>; type Safety = hir::Safety; type Abi = abi::Abi; - type Const = ty::Const<'tcx>; type PlaceholderConst = ty::PlaceholderConst; + type ParamConst = ty::ParamConst; type BoundConst = ty::BoundVar; type ValueConst = ty::ValTree<'tcx>; type ExprConst = ty::Expr<'tcx>; - type Region = Region<'tcx>; + type EarlyParamRegion = ty::EarlyParamRegion; type LateParamRegion = ty::LateParamRegion; type BoundRegion = ty::BoundRegion; @@ -136,15 +158,21 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type ParamEnv = ty::ParamEnv<'tcx>; type Predicate = Predicate<'tcx>; + type Clause = Clause<'tcx>; type Clauses = ty::Clauses<'tcx>; - fn expand_abstract_consts>>(self, t: T) -> T { - self.expand_abstract_consts(t) + type EvaluationCache = &'tcx solve::EvaluationCache<'tcx>; + + fn evaluation_cache(self, mode: SolverMode) -> &'tcx solve::EvaluationCache<'tcx> { + match mode { + SolverMode::Normal => &self.new_solver_evaluation_cache, + SolverMode::Coherence => &self.new_solver_coherence_evaluation_cache, + } } - fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars { - self.mk_canonical_var_infos(infos) + fn expand_abstract_consts>>(self, t: T) -> T { + self.expand_abstract_consts(t) } type GenericsOf = &'tcx ty::Generics; @@ -163,6 +191,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.type_of(def_id) } + type AdtDef = ty::AdtDef<'tcx>; + fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef { + self.adt_def(adt_def_id) + } + fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind { match self.def_kind(alias.def_id) { DefKind::AssocTy => { @@ -200,8 +233,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn trait_ref_and_own_args_for_alias( self, def_id: DefId, - args: Self::GenericArgs, - ) -> (rustc_type_ir::TraitRef, Self::GenericArgsSlice) { + args: ty::GenericArgsRef<'tcx>, + ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) { assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst); let trait_def_id = self.parent(def_id); assert_matches!(self.def_kind(trait_def_id), DefKind::Trait); @@ -212,18 +245,22 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) } - fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs { + fn mk_args(self, args: &[Self::GenericArg]) -> ty::GenericArgsRef<'tcx> { self.mk_args(args) } fn mk_args_from_iter(self, args: I) -> T::Output where I: Iterator, - T: CollectAndApply, + T: CollectAndApply>, { self.mk_args_from_iter(args) } + fn check_args_compatible(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> bool { + self.check_args_compatible(def_id, args) + } + fn check_and_mk_args( self, def_id: DefId, @@ -242,7 +279,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn mk_type_list_from_iter(self, args: I) -> T::Output where I: Iterator, - T: CollectAndApply, + T: CollectAndApply, &'tcx List>>, { self.mk_type_list_from_iter(args) } @@ -291,6 +328,24 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.item_bounds(def_id).map_bound(IntoIterator::into_iter) } + fn predicates_of( + self, + def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl IntoIterator>> { + ty::EarlyBinder::bind( + self.predicates_of(def_id).instantiate_identity(self).predicates.into_iter(), + ) + } + + fn own_predicates_of( + self, + def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl IntoIterator>> { + ty::EarlyBinder::bind( + self.predicates_of(def_id).instantiate_own_identity().map(|(clause, _)| clause), + ) + } + fn super_predicates_of( self, def_id: DefId, @@ -305,15 +360,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { } fn require_lang_item(self, lang_item: TraitSolverLangItem) -> DefId { - self.require_lang_item( - match lang_item { - TraitSolverLangItem::Future => hir::LangItem::Future, - TraitSolverLangItem::FutureOutput => hir::LangItem::FutureOutput, - TraitSolverLangItem::AsyncFnKindHelper => hir::LangItem::AsyncFnKindHelper, - TraitSolverLangItem::AsyncFnKindUpvars => hir::LangItem::AsyncFnKindUpvars, - }, - None, - ) + self.require_lang_item(trait_lang_item_to_lang_item(lang_item), None) + } + + fn is_lang_item(self, def_id: DefId, lang_item: TraitSolverLangItem) -> bool { + self.is_lang_item(def_id, trait_lang_item_to_lang_item(lang_item)) } fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator { @@ -322,6 +373,257 @@ impl<'tcx> Interner for TyCtxt<'tcx> { .filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type)) .map(|assoc_item| assoc_item.def_id) } + + fn args_may_unify_deep( + self, + obligation_args: ty::GenericArgsRef<'tcx>, + impl_args: ty::GenericArgsRef<'tcx>, + ) -> bool { + ty::fast_reject::DeepRejectCtxt { + treat_obligation_params: ty::fast_reject::TreatParams::ForLookup, + } + .args_may_unify(obligation_args, impl_args) + } + + // This implementation is a bit different from `TyCtxt::for_each_relevant_impl`, + // since we want to skip over blanket impls for non-rigid aliases, and also we + // only want to consider types that *actually* unify with float/int vars. + fn for_each_relevant_impl( + self, + trait_def_id: DefId, + self_ty: Ty<'tcx>, + mut f: impl FnMut(DefId), + ) { + let tcx = self; + let trait_impls = tcx.trait_impls_of(trait_def_id); + let mut consider_impls_for_simplified_type = |simp| { + if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) { + for &impl_def_id in impls_for_type { + f(impl_def_id); + } + } + }; + + match self_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Pat(_, _) + | ty::Slice(_) + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Dynamic(_, _, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(_, _) + | ty::Never + | ty::Tuple(_) => { + let simp = ty::fast_reject::simplify_type( + tcx, + self_ty, + ty::fast_reject::TreatParams::ForLookup, + ) + .unwrap(); + consider_impls_for_simplified_type(simp); + } + + // HACK: For integer and float variables we have to manually look at all impls + // which have some integer or float as a self type. + ty::Infer(ty::IntVar(_)) => { + use ty::IntTy::*; + use ty::UintTy::*; + // This causes a compiler error if any new integer kinds are added. + let (I8 | I16 | I32 | I64 | I128 | Isize): ty::IntTy; + let (U8 | U16 | U32 | U64 | U128 | Usize): ty::UintTy; + let possible_integers = [ + // signed integers + ty::SimplifiedType::Int(I8), + ty::SimplifiedType::Int(I16), + ty::SimplifiedType::Int(I32), + ty::SimplifiedType::Int(I64), + ty::SimplifiedType::Int(I128), + ty::SimplifiedType::Int(Isize), + // unsigned integers + ty::SimplifiedType::Uint(U8), + ty::SimplifiedType::Uint(U16), + ty::SimplifiedType::Uint(U32), + ty::SimplifiedType::Uint(U64), + ty::SimplifiedType::Uint(U128), + ty::SimplifiedType::Uint(Usize), + ]; + for simp in possible_integers { + consider_impls_for_simplified_type(simp); + } + } + + ty::Infer(ty::FloatVar(_)) => { + // This causes a compiler error if any new float kinds are added. + let (ty::FloatTy::F16 | ty::FloatTy::F32 | ty::FloatTy::F64 | ty::FloatTy::F128); + let possible_floats = [ + ty::SimplifiedType::Float(ty::FloatTy::F16), + ty::SimplifiedType::Float(ty::FloatTy::F32), + ty::SimplifiedType::Float(ty::FloatTy::F64), + ty::SimplifiedType::Float(ty::FloatTy::F128), + ]; + + for simp in possible_floats { + consider_impls_for_simplified_type(simp); + } + } + + // The only traits applying to aliases and placeholders are blanket impls. + // + // Impls which apply to an alias after normalization are handled by + // `assemble_candidates_after_normalizing_self_ty`. + ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (), + + // FIXME: These should ideally not exist as a self type. It would be nice for + // the builtin auto trait impls of coroutines to instead directly recurse + // into the witness. + ty::CoroutineWitness(..) => (), + + // These variants should not exist as a self type. + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) + | ty::Param(_) + | ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"), + } + + let trait_impls = tcx.trait_impls_of(trait_def_id); + for &impl_def_id in trait_impls.blanket_impls() { + f(impl_def_id); + } + } + + fn has_item_definition(self, def_id: DefId) -> bool { + self.defaultness(def_id).has_value() + } + + fn impl_is_default(self, impl_def_id: DefId) -> bool { + self.defaultness(impl_def_id).is_default() + } + + fn impl_trait_ref(self, impl_def_id: DefId) -> ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>> { + self.impl_trait_ref(impl_def_id).unwrap() + } + + fn impl_polarity(self, impl_def_id: DefId) -> ty::ImplPolarity { + self.impl_polarity(impl_def_id) + } + + fn trait_is_auto(self, trait_def_id: DefId) -> bool { + self.trait_is_auto(trait_def_id) + } + + fn trait_is_alias(self, trait_def_id: DefId) -> bool { + self.trait_is_alias(trait_def_id) + } + + fn trait_is_object_safe(self, trait_def_id: DefId) -> bool { + self.is_object_safe(trait_def_id) + } + + fn trait_may_be_implemented_via_object(self, trait_def_id: DefId) -> bool { + self.trait_def(trait_def_id).implement_via_object + } + + fn fn_trait_kind_from_def_id(self, trait_def_id: DefId) -> Option { + self.fn_trait_kind_from_def_id(trait_def_id) + } + + fn async_fn_trait_kind_from_def_id(self, trait_def_id: DefId) -> Option { + self.async_fn_trait_kind_from_def_id(trait_def_id) + } + + fn supertrait_def_ids(self, trait_def_id: DefId) -> impl IntoIterator { + self.supertrait_def_ids(trait_def_id) + } + + fn delay_bug(self, msg: impl ToString) -> ErrorGuaranteed { + self.dcx().span_delayed_bug(DUMMY_SP, msg.to_string()) + } + + fn is_general_coroutine(self, coroutine_def_id: DefId) -> bool { + self.is_general_coroutine(coroutine_def_id) + } + + fn coroutine_is_async(self, coroutine_def_id: DefId) -> bool { + self.coroutine_is_async(coroutine_def_id) + } + + fn coroutine_is_gen(self, coroutine_def_id: DefId) -> bool { + self.coroutine_is_gen(coroutine_def_id) + } + + fn coroutine_is_async_gen(self, coroutine_def_id: DefId) -> bool { + self.coroutine_is_async_gen(coroutine_def_id) + } + + fn layout_is_pointer_like(self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { + self.layout_of(self.erase_regions(param_env.and(ty))) + .is_ok_and(|layout| layout.layout.is_pointer_like(&self.data_layout)) + } + + type UnsizingParams = &'tcx rustc_index::bit_set::BitSet; + fn unsizing_params_for_adt(self, adt_def_id: DefId) -> Self::UnsizingParams { + self.unsizing_params_for_adt(adt_def_id) + } + + fn find_const_ty_from_env( + self, + param_env: ty::ParamEnv<'tcx>, + placeholder: Self::PlaceholderConst, + ) -> Ty<'tcx> { + placeholder.find_const_ty_from_env(param_env) + } +} + +fn trait_lang_item_to_lang_item(lang_item: TraitSolverLangItem) -> LangItem { + match lang_item { + TraitSolverLangItem::AsyncDestruct => LangItem::AsyncDestruct, + TraitSolverLangItem::AsyncFnKindHelper => LangItem::AsyncFnKindHelper, + TraitSolverLangItem::AsyncFnKindUpvars => LangItem::AsyncFnKindUpvars, + TraitSolverLangItem::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput, + TraitSolverLangItem::AsyncIterator => LangItem::AsyncIterator, + TraitSolverLangItem::CallOnceFuture => LangItem::CallOnceFuture, + TraitSolverLangItem::CallRefFuture => LangItem::CallRefFuture, + TraitSolverLangItem::Clone => LangItem::Clone, + TraitSolverLangItem::Copy => LangItem::Copy, + TraitSolverLangItem::Coroutine => LangItem::Coroutine, + TraitSolverLangItem::CoroutineReturn => LangItem::CoroutineReturn, + TraitSolverLangItem::CoroutineYield => LangItem::CoroutineYield, + TraitSolverLangItem::Destruct => LangItem::Destruct, + TraitSolverLangItem::DiscriminantKind => LangItem::DiscriminantKind, + TraitSolverLangItem::DynMetadata => LangItem::DynMetadata, + TraitSolverLangItem::FnPtrTrait => LangItem::FnPtrTrait, + TraitSolverLangItem::FusedIterator => LangItem::FusedIterator, + TraitSolverLangItem::Future => LangItem::Future, + TraitSolverLangItem::FutureOutput => LangItem::FutureOutput, + TraitSolverLangItem::Iterator => LangItem::Iterator, + TraitSolverLangItem::Metadata => LangItem::Metadata, + TraitSolverLangItem::Option => LangItem::Option, + TraitSolverLangItem::PointeeTrait => LangItem::PointeeTrait, + TraitSolverLangItem::PointerLike => LangItem::PointerLike, + TraitSolverLangItem::Poll => LangItem::Poll, + TraitSolverLangItem::Sized => LangItem::Sized, + TraitSolverLangItem::TransmuteTrait => LangItem::TransmuteTrait, + TraitSolverLangItem::Tuple => LangItem::Tuple, + TraitSolverLangItem::Unpin => LangItem::Unpin, + TraitSolverLangItem::Unsize => LangItem::Unsize, + } +} + +impl<'tcx> rustc_type_ir::inherent::DefId> for DefId { + fn as_local(self) -> Option { + self.as_local() + } } impl<'tcx> rustc_type_ir::inherent::Abi> for abi::Abi { @@ -356,6 +658,10 @@ impl<'tcx> rustc_type_ir::inherent::Features> for &'tcx rustc_featu fn coroutine_clone(self) -> bool { self.coroutine_clone } + + fn associated_const_equality(self) -> bool { + self.associated_const_equality + } } type InternedSet<'tcx, T> = ShardedHashMap, ()>; @@ -384,7 +690,7 @@ pub struct CtxtInterners<'tcx> { layout: InternedSet<'tcx, LayoutS>, adt_def: InternedSet<'tcx, AdtDefData>, external_constraints: InternedSet<'tcx, ExternalConstraintsData>>, - predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>, + predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData>>, fields: InternedSet<'tcx, List>, local_def_ids: InternedSet<'tcx, List>, captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>, @@ -1415,7 +1721,7 @@ impl<'tcx> TyCtxt<'tcx> { ) } - pub fn dcx(self) -> &'tcx DiagCtxt { + pub fn dcx(self) -> DiagCtxtHandle<'tcx> { self.sess.dcx() } } @@ -2096,7 +2402,7 @@ direct_interners! { adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>, external_constraints: pub mk_external_constraints(ExternalConstraintsData>): ExternalConstraints -> ExternalConstraints<'tcx>, - predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData<'tcx>): + predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData>): PredefinedOpaques -> PredefinedOpaques<'tcx>, } diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 54c88e48614b..83d45ca78d9d 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -44,10 +44,27 @@ pub struct GenericArg<'tcx> { impl<'tcx> rustc_type_ir::inherent::GenericArg> for GenericArg<'tcx> {} impl<'tcx> rustc_type_ir::inherent::GenericArgs> for ty::GenericArgsRef<'tcx> { + fn rebase_onto( + self, + tcx: TyCtxt<'tcx>, + source_ancestor: DefId, + target_args: GenericArgsRef<'tcx>, + ) -> GenericArgsRef<'tcx> { + self.rebase_onto(tcx, source_ancestor, target_args) + } + fn type_at(self, i: usize) -> Ty<'tcx> { self.type_at(i) } + fn region_at(self, i: usize) -> ty::Region<'tcx> { + self.region_at(i) + } + + fn const_at(self, i: usize) -> ty::Const<'tcx> { + self.const_at(i) + } + fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::GenericArgsRef<'tcx> { GenericArgs::identity_for_item(tcx, def_id) } @@ -281,6 +298,7 @@ impl<'tcx> GenericArg<'tcx> { pub fn is_non_region_infer(self) -> bool { match self.unpack() { GenericArgKind::Lifetime(_) => false, + // FIXME: This shouldn't return numerical/float. GenericArgKind::Type(ty) => ty.is_ty_or_numeric_infer(), GenericArgKind::Const(ct) => ct.is_ct_infer(), } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 185dbe447358..6467689a8aa1 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -392,6 +392,10 @@ impl<'tcx> GenericPredicates<'tcx> { EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args) } + pub fn instantiate_own_identity(&self) -> impl Iterator, Span)> { + EarlyBinder::bind(self.predicates).instantiate_identity_iter_copied() + } + #[instrument(level = "debug", skip(self, tcx))] fn instantiate_into( &self, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index cf7610bb4f61..3d397b6b37e1 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -5,7 +5,7 @@ use crate::ty::normalize_erasing_regions::NormalizationError; use crate::ty::{self, CoroutineArgsExt, Ty, TyCtxt, TypeVisitableExt}; use rustc_error_messages::DiagMessage; use rustc_errors::{ - Diag, DiagArgValue, DiagCtxt, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, + Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, }; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -1256,7 +1256,7 @@ pub enum FnAbiError<'tcx> { } impl<'a, 'b, G: EmissionGuarantee> Diagnostic<'a, G> for FnAbiError<'b> { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { match self { Self::Layout(e) => e.into_diagnostic().into_diag(dcx, level), Self::AdjustForForeignAbi(call::AdjustForForeignAbiError::Unsupported { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d07541bad93d..9c2bfc12a18a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -990,6 +990,16 @@ pub struct ParamEnv<'tcx> { packed: CopyTaggedPtr, ParamTag, true>, } +impl<'tcx> rustc_type_ir::inherent::ParamEnv> for ParamEnv<'tcx> { + fn reveal(self) -> Reveal { + self.reveal() + } + + fn caller_bounds(self) -> impl IntoIterator> { + self.caller_bounds() + } +} + #[derive(Copy, Clone)] struct ParamTag { reveal: traits::Reveal, diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index ae36f2624ca5..e9b37503bb3e 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -175,6 +175,14 @@ pub struct Clause<'tcx>( impl<'tcx> rustc_type_ir::inherent::Clause> for Clause<'tcx> {} +impl<'tcx> rustc_type_ir::inherent::IntoKind for Clause<'tcx> { + type Kind = ty::Binder<'tcx, ClauseKind<'tcx>>; + + fn kind(self) -> Self::Kind { + self.kind() + } +} + impl<'tcx> Clause<'tcx> { pub fn as_predicate(self) -> Predicate<'tcx> { Predicate(self.0) @@ -251,6 +259,28 @@ impl<'tcx> ExistentialPredicate<'tcx> { pub type PolyExistentialPredicate<'tcx> = ty::Binder<'tcx, ExistentialPredicate<'tcx>>; +impl<'tcx> rustc_type_ir::inherent::BoundExistentialPredicates> + for &'tcx ty::List> +{ + fn principal_def_id(self) -> Option { + self.principal_def_id() + } + + fn principal(self) -> Option> { + self.principal() + } + + fn auto_traits(self) -> impl IntoIterator { + self.auto_traits() + } + + fn projection_bounds( + self, + ) -> impl IntoIterator>> { + self.projection_bounds() + } +} + impl<'tcx> ty::List> { /// Returns the "principal `DefId`" of this set of existential predicates. /// @@ -481,12 +511,6 @@ impl<'tcx> UpcastFrom, TraitRef<'tcx>> for Predicate<'tcx> { } } -impl<'tcx> UpcastFrom, TraitRef<'tcx>> for TraitPredicate<'tcx> { - fn upcast_from(from: TraitRef<'tcx>, _tcx: TyCtxt<'tcx>) -> Self { - TraitPredicate { trait_ref: from, polarity: PredicatePolarity::Positive } - } -} - impl<'tcx> UpcastFrom, TraitRef<'tcx>> for Clause<'tcx> { fn upcast_from(from: TraitRef<'tcx>, tcx: TyCtxt<'tcx>) -> Self { let p: Predicate<'tcx> = from.upcast(tcx); @@ -543,6 +567,12 @@ impl<'tcx> UpcastFrom, PolyTraitPredicate<'tcx>> for Clause<'tcx> { } } +impl<'tcx> UpcastFrom, RegionOutlivesPredicate<'tcx>> for Predicate<'tcx> { + fn upcast_from(from: RegionOutlivesPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self { + ty::Binder::dummy(PredicateKind::Clause(ClauseKind::RegionOutlives(from))).upcast(tcx) + } +} + impl<'tcx> UpcastFrom, PolyRegionOutlivesPredicate<'tcx>> for Predicate<'tcx> { fn upcast_from(from: PolyRegionOutlivesPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self { from.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).upcast(tcx) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8308e537e5ed..9c8a3484aa5b 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -930,6 +930,22 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { fn new_pat(interner: TyCtxt<'tcx>, ty: Self, pat: ty::Pattern<'tcx>) -> Self { Ty::new_pat(interner, ty, pat) } + + fn new_unit(interner: TyCtxt<'tcx>) -> Self { + interner.types.unit + } + + fn new_usize(interner: TyCtxt<'tcx>) -> Self { + interner.types.usize + } + + fn discriminant_ty(self, interner: TyCtxt<'tcx>) -> Ty<'tcx> { + self.discriminant_ty(interner) + } + + fn async_destructor_ty(self, interner: TyCtxt<'tcx>) -> Ty<'tcx> { + self.async_destructor_ty(interner) + } } /// Type utilities diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 52a0e72e17e2..b079ed521d34 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -565,42 +565,6 @@ impl<'tcx> TyCtxt<'tcx> { Ok(()) } - /// Checks whether each generic argument is simply a unique generic placeholder. - /// - /// This is used in the new solver, which canonicalizes params to placeholders - /// for better caching. - pub fn uses_unique_placeholders_ignoring_regions( - self, - args: GenericArgsRef<'tcx>, - ) -> Result<(), NotUniqueParam<'tcx>> { - let mut seen = GrowableBitSet::default(); - for arg in args { - match arg.unpack() { - // Ignore regions, since we can't resolve those in a canonicalized - // query in the trait solver. - GenericArgKind::Lifetime(_) => {} - GenericArgKind::Type(t) => match t.kind() { - ty::Placeholder(p) => { - if !seen.insert(p.bound.var) { - return Err(NotUniqueParam::DuplicateParam(t.into())); - } - } - _ => return Err(NotUniqueParam::NotParam(t.into())), - }, - GenericArgKind::Const(c) => match c.kind() { - ty::ConstKind::Placeholder(p) => { - if !seen.insert(p.bound) { - return Err(NotUniqueParam::DuplicateParam(c.into())); - } - } - _ => return Err(NotUniqueParam::NotParam(c.into())), - }, - } - } - - Ok(()) - } - /// Returns `true` if `def_id` refers to a closure, coroutine, or coroutine-closure /// (i.e. an async closure). These are all represented by `hir::Closure`, and all /// have the same `DefKind`. diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 3bd2e47976b5..7c73d8a6d47d 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1,9 +1,9 @@ use crate::fluent_generated as fluent; -use rustc_errors::DiagArgValue; use rustc_errors::{ - codes::*, Applicability, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, MultiSpan, + codes::*, Applicability, Diag, Diagnostic, EmissionGuarantee, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic, }; +use rustc_errors::{DiagArgValue, DiagCtxtHandle}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; use rustc_pattern_analysis::{errors::Uncovered, rustc::RustcPatCtxt}; @@ -492,7 +492,7 @@ pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> { } impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::mir_build_non_exhaustive_patterns_type_not_empty); diag.span(self.scrut_span); diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 30f57c8c622f..70065b5a2c32 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1137,7 +1137,7 @@ fn report_non_exhaustive_match<'p, 'tcx>( let all_arms_have_guards = arms.iter().all(|arm_id| thir[*arm_id].guard.is_some()); if !is_empty_match && all_arms_have_guards { - err.subdiagnostic(cx.tcx.dcx(), NonExhaustiveMatchAllArmsGuarded); + err.subdiagnostic(NonExhaustiveMatchAllArmsGuarded); } if let Some((span, sugg)) = suggestion { err.span_suggestion_verbose(span, msg, sugg, Applicability::HasPlaceholders); diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 0e209757100c..759bb7c1f9d9 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -5,6 +5,7 @@ use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, ConditionInfo, CoverageKind}; use rustc_middle::mir::{self, BasicBlock, StatementKind}; +use rustc_middle::ty::TyCtxt; use rustc_span::Span; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; @@ -63,30 +64,34 @@ pub(super) struct ExtractedMappings { /// Extracts coverage-relevant spans from MIR, and associates them with /// their corresponding BCBs. -pub(super) fn extract_all_mapping_info_from_mir( - mir_body: &mir::Body<'_>, +pub(super) fn extract_all_mapping_info_from_mir<'tcx>( + tcx: TyCtxt<'tcx>, + mir_body: &mir::Body<'tcx>, hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, ) -> ExtractedMappings { - if hir_info.is_async_fn { - // An async function desugars into a function that returns a future, - // with the user code wrapped in a closure. Any spans in the desugared - // outer function will be unhelpful, so just keep the signature span - // and ignore all of the spans in the MIR body. - let mut mappings = ExtractedMappings::default(); - if let Some(span) = hir_info.fn_sig_span_extended { - mappings.code_mappings.push(CodeMapping { span, bcb: START_BCB }); - } - return mappings; - } - let mut code_mappings = vec![]; let mut branch_pairs = vec![]; let mut mcdc_bitmap_bytes = 0; let mut mcdc_branches = vec![]; let mut mcdc_decisions = vec![]; - extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings); + if hir_info.is_async_fn || tcx.sess.coverage_no_mir_spans() { + // An async function desugars into a function that returns a future, + // with the user code wrapped in a closure. Any spans in the desugared + // outer function will be unhelpful, so just keep the signature span + // and ignore all of the spans in the MIR body. + // + // When debugging flag `-Zcoverage-options=no-mir-spans` is set, we need + // to give the same treatment to _all_ functions, because `llvm-cov` + // seems to ignore functions that don't have any ordinary code spans. + if let Some(span) = hir_info.fn_sig_span_extended { + code_mappings.push(CodeMapping { span, bcb: START_BCB }); + } + } else { + // Extract coverage spans from MIR statements/terminators as normal. + extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings); + } branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks)); diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 419e39bc3867..4a64d21f3d17 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -71,8 +71,12 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: //////////////////////////////////////////////////// // Extract coverage spans and other mapping info from MIR. - let extracted_mappings = - mappings::extract_all_mapping_info_from_mir(mir_body, &hir_info, &basic_coverage_blocks); + let extracted_mappings = mappings::extract_all_mapping_info_from_mir( + tcx, + mir_body, + &hir_info, + &basic_coverage_blocks, + ); //////////////////////////////////////////////////// // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index b28dcb38cb6b..dc7648d27b56 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -104,7 +104,7 @@ impl<'a> LintDiagnostic<'a, ()> for MustNotSupend<'_, '_> { diag.primary_message(fluent::mir_transform_must_not_suspend); diag.span_label(self.yield_sp, fluent::_subdiag::label); if let Some(reason) = self.reason { - diag.subdiagnostic(diag.dcx, reason); + diag.subdiagnostic(reason); } diag.span_help(self.src_sp, fluent::_subdiag::help); diag.arg("pre", self.pre); diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 35fc78f20453..c0d1efd96c5b 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use crate::fluent_generated as fluent; -use rustc_errors::{Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; use rustc_macros::{Diagnostic, LintDiagnostic}; use rustc_span::{Span, Symbol}; @@ -48,7 +48,7 @@ pub struct UnusedGenericParamsHint { impl Diagnostic<'_, G> for UnusedGenericParamsHint { #[track_caller] - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::monomorphize_unused_generic_params); diag.span(self.span); for (span, name) in self.param_spans.into_iter().zip(self.param_names) { diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 50dbc991f8fd..3a5f438b4325 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -5,9 +5,25 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +bitflags = "2.4.1" +derivative = "2.2.0" +rustc_ast_ir = { path = "../rustc_ast_ir" } +rustc_data_structures = { path = "../rustc_data_structures", optional = true } +rustc_index = { path = "../rustc_index", default-features = false } +rustc_macros = { path = "../rustc_macros", optional = true } +rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_type_ir = { path = "../rustc_type_ir", default-features = false } +rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } +tracing = "0.1" # tidy-alphabetical-end [features] default = ["nightly"] -nightly = ["rustc_type_ir/nightly"] +nightly = [ + "rustc_ast_ir/nightly", + "rustc_data_structures", + "rustc_index/nightly", + "rustc_macros", + "rustc_serialize", + "rustc_type_ir/nightly", +] diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index f22e24ef6541..a81fd03d034f 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -4,10 +4,11 @@ use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::visit::TypeVisitableExt; use rustc_type_ir::{ - self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, InferCtxtLike, - Interner, + self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Interner, }; +use crate::infcx::SolverDelegate; + /// Whether we're canonicalizing a query input or the query response. /// /// When canonicalizing an input we're in the context of the caller @@ -37,7 +38,7 @@ pub enum CanonicalizeMode { }, } -pub struct Canonicalizer<'a, Infcx: InferCtxtLike, I: Interner> { +pub struct Canonicalizer<'a, Infcx: SolverDelegate, I: Interner> { infcx: &'a Infcx, canonicalize_mode: CanonicalizeMode, @@ -46,7 +47,7 @@ pub struct Canonicalizer<'a, Infcx: InferCtxtLike, I: Interner> { binder_index: ty::DebruijnIndex, } -impl<'a, Infcx: InferCtxtLike, I: Interner> Canonicalizer<'a, Infcx, I> { +impl<'a, Infcx: SolverDelegate, I: Interner> Canonicalizer<'a, Infcx, I> { pub fn canonicalize>( infcx: &'a Infcx, canonicalize_mode: CanonicalizeMode, @@ -210,7 +211,7 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> Canonicalizer<'a, Infc } } -impl, I: Interner> TypeFolder +impl, I: Interner> TypeFolder for Canonicalizer<'_, Infcx, I> { fn interner(&self) -> I { diff --git a/compiler/rustc_next_trait_solver/src/infcx.rs b/compiler/rustc_next_trait_solver/src/infcx.rs new file mode 100644 index 000000000000..c249eb94cf65 --- /dev/null +++ b/compiler/rustc_next_trait_solver/src/infcx.rs @@ -0,0 +1,205 @@ +use std::fmt::Debug; + +use rustc_type_ir::fold::TypeFoldable; +use rustc_type_ir::relate::Relate; +use rustc_type_ir::solve::{Certainty, Goal, NoSolution, SolverMode}; +use rustc_type_ir::{self as ty, Interner}; + +pub trait SolverDelegate: Sized { + type Interner: Interner; + fn interner(&self) -> Self::Interner; + + type Span: Copy; + + fn solver_mode(&self) -> SolverMode; + + fn build_with_canonical( + interner: Self::Interner, + solver_mode: SolverMode, + canonical: &ty::Canonical, + ) -> (Self, V, ty::CanonicalVarValues) + where + V: TypeFoldable; + + fn universe(&self) -> ty::UniverseIndex; + fn create_next_universe(&self) -> ty::UniverseIndex; + + fn universe_of_ty(&self, ty: ty::TyVid) -> Option; + fn universe_of_lt(&self, lt: ty::RegionVid) -> Option; + fn universe_of_ct(&self, ct: ty::ConstVid) -> Option; + + fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid; + fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid; + + fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> ::Ty; + fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> ::Ty; + fn opportunistic_resolve_float_var( + &self, + vid: ty::FloatVid, + ) -> ::Ty; + fn opportunistic_resolve_ct_var( + &self, + vid: ty::ConstVid, + ) -> ::Const; + fn opportunistic_resolve_effect_var( + &self, + vid: ty::EffectVid, + ) -> ::Const; + fn opportunistic_resolve_lt_var( + &self, + vid: ty::RegionVid, + ) -> ::Region; + + fn defining_opaque_types(&self) -> ::DefiningOpaqueTypes; + + fn next_ty_infer(&self) -> ::Ty; + fn next_const_infer(&self) -> ::Const; + fn fresh_args_for_item( + &self, + def_id: ::DefId, + ) -> ::GenericArgs; + + fn fresh_var_for_kind_with_span( + &self, + arg: ::GenericArg, + span: Self::Span, + ) -> ::GenericArg; + + fn instantiate_binder_with_infer + Copy>( + &self, + value: ty::Binder, + ) -> T; + + fn enter_forall + Copy, U>( + &self, + value: ty::Binder, + f: impl FnOnce(T) -> U, + ) -> U; + + fn relate>( + &self, + param_env: ::ParamEnv, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result::Predicate>>, NoSolution>; + + fn eq_structurally_relating_aliases>( + &self, + param_env: ::ParamEnv, + lhs: T, + rhs: T, + ) -> Result::Predicate>>, NoSolution>; + + fn resolve_vars_if_possible(&self, value: T) -> T + where + T: TypeFoldable; + + fn probe(&self, probe: impl FnOnce() -> T) -> T; + + // FIXME: Uplift the leak check into this crate. + fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution>; + + // FIXME: This is only here because elaboration lives in `rustc_infer`! + fn elaborate_supertraits( + interner: Self::Interner, + trait_ref: ty::Binder>, + ) -> impl Iterator>>; + + fn try_const_eval_resolve( + &self, + param_env: ::ParamEnv, + unevaluated: ty::UnevaluatedConst, + ) -> Option<::Const>; + + fn sub_regions( + &self, + sub: ::Region, + sup: ::Region, + ); + + fn register_ty_outlives( + &self, + ty: ::Ty, + r: ::Region, + ); + + // FIXME: This only is here because `wf::obligations` is in `rustc_trait_selection`! + fn well_formed_goals( + &self, + param_env: ::ParamEnv, + arg: ::GenericArg, + ) -> Option::Predicate>>>; + + fn clone_opaque_types_for_query_response( + &self, + ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; + + fn make_deduplicated_outlives_constraints( + &self, + ) -> Vec::GenericArg>>; + + fn instantiate_canonical( + &self, + canonical: ty::Canonical, + values: ty::CanonicalVarValues, + ) -> V + where + V: TypeFoldable; + + fn instantiate_canonical_var_with_infer( + &self, + cv_info: ty::CanonicalVarInfo, + universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, + ) -> ::GenericArg; + + // FIXME: Can we implement this in terms of `add` and `inject`? + fn insert_hidden_type( + &self, + opaque_type_key: ty::OpaqueTypeKey, + param_env: ::ParamEnv, + hidden_ty: ::Ty, + goals: &mut Vec::Predicate>>, + ) -> Result<(), NoSolution>; + + fn add_item_bounds_for_hidden_type( + &self, + def_id: ::DefId, + args: ::GenericArgs, + param_env: ::ParamEnv, + hidden_ty: ::Ty, + goals: &mut Vec::Predicate>>, + ); + + fn inject_new_hidden_type_unchecked( + &self, + key: ty::OpaqueTypeKey, + hidden_ty: ::Ty, + ); + + fn reset_opaque_types(&self); + + fn trait_ref_is_knowable( + &self, + trait_ref: ty::TraitRef, + lazily_normalize_ty: impl FnMut( + ::Ty, + ) -> Result<::Ty, E>, + ) -> Result; + + fn fetch_eligible_assoc_item( + &self, + param_env: ::ParamEnv, + goal_trait_ref: ty::TraitRef, + trait_assoc_def_id: ::DefId, + impl_def_id: ::DefId, + ) -> Result::DefId>, NoSolution>; + + fn is_transmutable( + &self, + param_env: ::ParamEnv, + dst: ::Ty, + src: ::Ty, + assume: ::Const, + ) -> Result; +} diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index 144caf36ee53..79c6925221e1 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -4,6 +4,9 @@ //! but were uplifted in the process of making the new trait solver generic. //! So if you got to this crate from the old solver, it's totally normal. +#![feature(let_chains)] + pub mod canonicalizer; +pub mod infcx; pub mod resolve; pub mod solve; diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index 5c00b6978d69..3d8d957eaae4 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -1,27 +1,28 @@ +use crate::infcx::SolverDelegate; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::visit::TypeVisitableExt; -use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; +use rustc_type_ir::{self as ty, Interner}; /////////////////////////////////////////////////////////////////////////// // EAGER RESOLUTION /// Resolves ty, region, and const vars to their inferred values or their root vars. -pub struct EagerResolver<'a, Infcx, I = ::Interner> +pub struct EagerResolver<'a, Infcx, I = ::Interner> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { infcx: &'a Infcx, } -impl<'a, Infcx: InferCtxtLike> EagerResolver<'a, Infcx> { +impl<'a, Infcx: SolverDelegate> EagerResolver<'a, Infcx> { pub fn new(infcx: &'a Infcx) -> Self { EagerResolver { infcx } } } -impl, I: Interner> TypeFolder for EagerResolver<'_, Infcx> { +impl, I: Interner> TypeFolder for EagerResolver<'_, Infcx> { fn interner(&self) -> I { self.infcx.interner() } diff --git a/compiler/rustc_next_trait_solver/src/solve.rs b/compiler/rustc_next_trait_solver/src/solve.rs deleted file mode 100644 index eba96facabc6..000000000000 --- a/compiler/rustc_next_trait_solver/src/solve.rs +++ /dev/null @@ -1 +0,0 @@ -pub use rustc_type_ir::solve::*; diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs similarity index 89% rename from compiler/rustc_trait_selection/src/solve/alias_relate.rs rename to compiler/rustc_next_trait_solver/src/solve/alias_relate.rs index 4e52caa5a5b8..fbc8ac1d5d5c 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs @@ -15,17 +15,23 @@ //! (3.) Otherwise, if we end with two rigid (non-projection) or infer types, //! relate them structurally. -use super::EvalCtxt; -use rustc_infer::infer::InferCtxt; -use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; -use rustc_middle::ty; +use rustc_type_ir::inherent::*; +use rustc_type_ir::{self as ty, Interner}; +use tracing::{instrument, trace}; -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +use crate::infcx::SolverDelegate; +use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult}; + +impl EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ #[instrument(level = "trace", skip(self), ret)] pub(super) fn compute_alias_relate_goal( &mut self, - goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>, - ) -> QueryResult<'tcx> { + goal: Goal, + ) -> QueryResult { let tcx = self.interner(); let Goal { param_env, predicate: (lhs, rhs, direction) } = goal; debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some()); diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs similarity index 59% rename from compiler/rustc_trait_selection/src/solve/assembly/mod.rs rename to compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 1cdbf0820780..9a1537d26060 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -1,33 +1,26 @@ //! Code shared by trait and projection goals for candidate assembly. -use derivative::Derivative; -use rustc_hir::def_id::DefId; -use rustc_hir::LangItem; -use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::query::NoSolution; -use rustc_infer::traits::util::supertraits; -use rustc_middle::bug; -use rustc_middle::traits::solve::inspect::ProbeKind; -use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause, QueryResult}; -use rustc_middle::traits::BuiltinImplSource; -use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams}; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::ty::{fast_reject, TypeFoldable}; -use rustc_middle::ty::{TypeVisitableExt, Upcast}; -use rustc_span::{ErrorGuaranteed, DUMMY_SP}; -use rustc_type_ir::solve::{CandidateSource, CanonicalResponse}; -use rustc_type_ir::Interner; - -use crate::solve::GoalSource; -use crate::solve::{EvalCtxt, SolverMode}; - pub(super) mod structural_traits; +use rustc_type_ir::fold::TypeFoldable; +use rustc_type_ir::inherent::*; +use rustc_type_ir::lang_items::TraitSolverLangItem; +use rustc_type_ir::visit::TypeVisitableExt as _; +use rustc_type_ir::{self as ty, Interner, Upcast as _}; +use tracing::{debug, instrument}; + +use crate::infcx::SolverDelegate; +use crate::solve::inspect::ProbeKind; +use crate::solve::{ + BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource, + MaybeCause, NoSolution, QueryResult, SolverMode, +}; + /// A candidate is a possible way to prove a goal. /// /// It consists of both the `source`, which describes how that goal would be proven, /// and the `result` when using the given `source`. -#[derive(Derivative)] +#[derive(derivative::Derivative)] #[derivative(Debug(bound = ""), Clone(bound = ""))] pub(super) struct Candidate { pub(super) source: CandidateSource, @@ -35,39 +28,42 @@ pub(super) struct Candidate { } /// Methods used to assemble candidates for either trait or projection goals. -pub(super) trait GoalKind<'tcx>: - TypeFoldable> + Copy + Eq + std::fmt::Display +pub(super) trait GoalKind::Interner>: + TypeFoldable + Copy + Eq + std::fmt::Display +where + Infcx: SolverDelegate, + I: Interner, { - fn self_ty(self) -> Ty<'tcx>; + fn self_ty(self) -> I::Ty; - fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>; + fn trait_ref(self, tcx: I) -> ty::TraitRef; - fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self; + fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self; - fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId; + fn trait_def_id(self, tcx: I) -> I::DefId; /// Try equating an assumption predicate against a goal's predicate. If it /// holds, then execute the `then` callback, which should do any additional /// work, then produce a response (typically by executing /// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]). fn probe_and_match_goal_against_assumption( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - source: CandidateSource>, - goal: Goal<'tcx, Self>, - assumption: ty::Clause<'tcx>, - then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + source: CandidateSource, + goal: Goal, + assumption: I::Clause, + then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult, + ) -> Result, NoSolution>; /// Consider a clause, which consists of a "assumption" and some "requirements", /// to satisfy a goal. If the requirements hold, then attempt to satisfy our /// goal by equating it with the assumption. fn probe_and_consider_implied_clause( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - parent_source: CandidateSource>, - goal: Goal<'tcx, Self>, - assumption: ty::Clause<'tcx>, - requirements: impl IntoIterator>)>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + parent_source: CandidateSource, + goal: Goal, + assumption: I::Clause, + requirements: impl IntoIterator)>, + ) -> Result, NoSolution> { Self::probe_and_match_goal_against_assumption(ecx, parent_source, goal, assumption, |ecx| { for (nested_source, goal) in requirements { ecx.add_goal(nested_source, goal); @@ -80,15 +76,15 @@ pub(super) trait GoalKind<'tcx>: /// additionally checking all of the supertraits and object bounds to hold, /// since they're not implied by the well-formedness of the object type. fn probe_and_consider_object_bound_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - source: CandidateSource>, - goal: Goal<'tcx, Self>, - assumption: ty::Clause<'tcx>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + source: CandidateSource, + goal: Goal, + assumption: I::Clause, + ) -> Result, NoSolution> { Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| { let tcx = ecx.interner(); - let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { - bug!("expected object type in `probe_and_consider_object_bound_candidate`"); + let ty::Dynamic(bounds, _, _) = goal.predicate.self_ty().kind() else { + panic!("expected object type in `probe_and_consider_object_bound_candidate`"); }; ecx.add_goals( GoalSource::ImplWhereBound, @@ -104,10 +100,10 @@ pub(super) trait GoalKind<'tcx>: } fn consider_impl_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - impl_def_id: DefId, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + impl_def_id: I::DefId, + ) -> Result, NoSolution>; /// If the predicate contained an error, we want to avoid emitting unnecessary trait /// errors but still want to emit errors for other trait goals. We have some special @@ -116,85 +112,85 @@ pub(super) trait GoalKind<'tcx>: /// Trait goals always hold while projection goals never do. This is a bit arbitrary /// but prevents incorrect normalization while hiding any trait errors. fn consider_error_guaranteed_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - guar: ErrorGuaranteed, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + guar: I::ErrorGuaranteed, + ) -> Result, NoSolution>; /// A type implements an `auto trait` if its components do as well. /// /// These components are given by built-in rules from /// [`structural_traits::instantiate_constituent_tys_for_auto_trait`]. fn consider_auto_trait_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// A trait alias holds if the RHS traits and `where` clauses hold. fn consider_trait_alias_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// A type is `Sized` if its tail component is `Sized`. /// /// These components are given by built-in rules from /// [`structural_traits::instantiate_constituent_tys_for_sized_trait`]. fn consider_builtin_sized_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. /// /// These components are given by built-in rules from /// [`structural_traits::instantiate_constituent_tys_for_copy_clone_trait`]. fn consider_builtin_copy_clone_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// A type is `PointerLike` if we can compute its layout, and that layout /// matches the layout of `usize`. fn consider_builtin_pointer_like_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// A type is a `FnPtr` if it is of `FnPtr` type. fn consider_builtin_fn_ptr_trait_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn` /// family of traits where `A` is given by the signature of the type. fn consider_builtin_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, kind: ty::ClosureKind, - ) -> Result>, NoSolution>; + ) -> Result, NoSolution>; /// An async closure is known to implement the `AsyncFn` family of traits /// where `A` is given by the signature of the type. fn consider_builtin_async_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, kind: ty::ClosureKind, - ) -> Result>, NoSolution>; + ) -> Result, NoSolution>; /// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which /// is used internally to delay computation for async closures until after /// upvar analysis is performed in HIR typeck. fn consider_builtin_async_fn_kind_helper_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// `Tuple` is implemented if the `Self` type is a tuple. fn consider_builtin_tuple_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// `Pointee` is always implemented. /// @@ -202,65 +198,65 @@ pub(super) trait GoalKind<'tcx>: /// the built-in types. For structs, the metadata type is given by the struct /// tail. fn consider_builtin_pointee_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// A coroutine (that comes from an `async` desugaring) is known to implement /// `Future`, where `O` is given by the coroutine's return type /// that was computed during type-checking. fn consider_builtin_future_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// A coroutine (that comes from a `gen` desugaring) is known to implement /// `Iterator`, where `O` is given by the generator's yield type /// that was computed during type-checking. fn consider_builtin_iterator_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// A coroutine (that comes from a `gen` desugaring) is known to implement /// `FusedIterator` fn consider_builtin_fused_iterator_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; fn consider_builtin_async_iterator_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to /// implement `Coroutine`, given the resume, yield, /// and return types of the coroutine computed during type-checking. fn consider_builtin_coroutine_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; fn consider_builtin_discriminant_kind_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; fn consider_builtin_async_destruct_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; fn consider_builtin_destruct_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; fn consider_builtin_transmute_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// Consider (possibly several) candidates to upcast or unsize a type to another /// type, excluding the coercion of a sized type into a `dyn Trait`. @@ -270,16 +266,20 @@ pub(super) trait GoalKind<'tcx>: /// otherwise recompute this for codegen. This is a bit of a mess but the /// easiest way to maintain the existing behavior for now. fn consider_structural_builtin_unsize_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Vec>>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Vec>; } -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { - pub(super) fn assemble_and_evaluate_candidates>( +impl EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ + pub(super) fn assemble_and_evaluate_candidates>( &mut self, - goal: Goal<'tcx, G>, - ) -> Vec>> { + goal: Goal, + ) -> Vec> { let Ok(normalized_self_ty) = self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty()) else { @@ -291,7 +291,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect(); } - let goal: Goal<'tcx, G> = goal.with( + let goal: Goal = goal.with( self.interner(), goal.predicate.with_self_ty(self.interner(), normalized_self_ty), ); @@ -301,7 +301,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { let mut candidates = vec![]; - self.assemble_non_blanket_impl_candidates(goal, &mut candidates); + self.assemble_impl_candidates(goal, &mut candidates); self.assemble_builtin_impl_candidates(goal, &mut candidates); @@ -309,8 +309,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.assemble_object_bound_candidates(goal, &mut candidates); - self.assemble_blanket_impl_candidates(goal, &mut candidates); - self.assemble_param_env_candidates(goal, &mut candidates); match self.solver_mode() { @@ -326,7 +324,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(super) fn forced_ambiguity( &mut self, cause: MaybeCause, - ) -> Result>, NoSolution> { + ) -> Result, NoSolution> { // This may fail if `try_evaluate_added_goals` overflows because it // fails to reach a fixpoint but ends up getting an error after // running for some additional step. @@ -339,149 +337,36 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } #[instrument(level = "trace", skip_all)] - fn assemble_non_blanket_impl_candidates>( + fn assemble_impl_candidates>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, + goal: Goal, + candidates: &mut Vec>, ) { let tcx = self.interner(); - let self_ty = goal.predicate.self_ty(); - let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx)); - let mut consider_impls_for_simplified_type = |simp| { - if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) { - for &impl_def_id in impls_for_type { - // For every `default impl`, there's always a non-default `impl` - // that will *also* apply. There's no reason to register a candidate - // for this impl, since it is *not* proof that the trait goal holds. - if tcx.defaultness(impl_def_id).is_default() { - return; - } - - match G::consider_impl_candidate(self, goal, impl_def_id) { - Ok(candidate) => candidates.push(candidate), - Err(NoSolution) => (), - } + tcx.for_each_relevant_impl( + goal.predicate.trait_def_id(tcx), + goal.predicate.self_ty(), + |impl_def_id| { + // For every `default impl`, there's always a non-default `impl` + // that will *also* apply. There's no reason to register a candidate + // for this impl, since it is *not* proof that the trait goal holds. + if tcx.impl_is_default(impl_def_id) { + return; } - } - }; - match self_ty.kind() { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Adt(_, _) - | ty::Foreign(_) - | ty::Str - | ty::Array(_, _) - | ty::Pat(_, _) - | ty::Slice(_) - | ty::RawPtr(_, _) - | ty::Ref(_, _, _) - | ty::FnDef(_, _) - | ty::FnPtr(_) - | ty::Dynamic(_, _, _) - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Coroutine(_, _) - | ty::Never - | ty::Tuple(_) => { - let simp = - fast_reject::simplify_type(tcx, self_ty, TreatParams::ForLookup).unwrap(); - consider_impls_for_simplified_type(simp); - } - - // HACK: For integer and float variables we have to manually look at all impls - // which have some integer or float as a self type. - ty::Infer(ty::IntVar(_)) => { - use ty::IntTy::*; - use ty::UintTy::*; - // This causes a compiler error if any new integer kinds are added. - let (I8 | I16 | I32 | I64 | I128 | Isize): ty::IntTy; - let (U8 | U16 | U32 | U64 | U128 | Usize): ty::UintTy; - let possible_integers = [ - // signed integers - SimplifiedType::Int(I8), - SimplifiedType::Int(I16), - SimplifiedType::Int(I32), - SimplifiedType::Int(I64), - SimplifiedType::Int(I128), - SimplifiedType::Int(Isize), - // unsigned integers - SimplifiedType::Uint(U8), - SimplifiedType::Uint(U16), - SimplifiedType::Uint(U32), - SimplifiedType::Uint(U64), - SimplifiedType::Uint(U128), - SimplifiedType::Uint(Usize), - ]; - for simp in possible_integers { - consider_impls_for_simplified_type(simp); + match G::consider_impl_candidate(self, goal, impl_def_id) { + Ok(candidate) => candidates.push(candidate), + Err(NoSolution) => (), } - } - - ty::Infer(ty::FloatVar(_)) => { - // This causes a compiler error if any new float kinds are added. - let (ty::FloatTy::F16 | ty::FloatTy::F32 | ty::FloatTy::F64 | ty::FloatTy::F128); - let possible_floats = [ - SimplifiedType::Float(ty::FloatTy::F16), - SimplifiedType::Float(ty::FloatTy::F32), - SimplifiedType::Float(ty::FloatTy::F64), - SimplifiedType::Float(ty::FloatTy::F128), - ]; - - for simp in possible_floats { - consider_impls_for_simplified_type(simp); - } - } - - // The only traits applying to aliases and placeholders are blanket impls. - // - // Impls which apply to an alias after normalization are handled by - // `assemble_candidates_after_normalizing_self_ty`. - ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (), - - // FIXME: These should ideally not exist as a self type. It would be nice for - // the builtin auto trait impls of coroutines to instead directly recurse - // into the witness. - ty::CoroutineWitness(..) => (), - - // These variants should not exist as a self type. - ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) - | ty::Param(_) - | ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"), - } + }, + ); } #[instrument(level = "trace", skip_all)] - fn assemble_blanket_impl_candidates>( + fn assemble_builtin_impl_candidates>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, - ) { - let tcx = self.interner(); - let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx)); - for &impl_def_id in trait_impls.blanket_impls() { - // For every `default impl`, there's always a non-default `impl` - // that will *also* apply. There's no reason to register a candidate - // for this impl, since it is *not* proof that the trait goal holds. - if tcx.defaultness(impl_def_id).is_default() { - return; - } - - match G::consider_impl_candidate(self, goal, impl_def_id) { - Ok(candidate) => candidates.push(candidate), - Err(NoSolution) => (), - } - } - } - - #[instrument(level = "trace", skip_all)] - fn assemble_builtin_impl_candidates>( - &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, + goal: Goal, + candidates: &mut Vec>, ) { let tcx = self.interner(); let trait_def_id = goal.predicate.trait_def_id(tcx); @@ -499,43 +384,43 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { G::consider_auto_trait_candidate(self, goal) } else if tcx.trait_is_alias(trait_def_id) { G::consider_trait_alias_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::Sized) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Sized) { G::consider_builtin_sized_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::Copy) - || tcx.is_lang_item(trait_def_id, LangItem::Clone) + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Copy) + || tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Clone) { G::consider_builtin_copy_clone_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::PointerLike) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::PointerLike) { G::consider_builtin_pointer_like_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::FnPtrTrait) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::FnPtrTrait) { G::consider_builtin_fn_ptr_trait_candidate(self, goal) } else if let Some(kind) = self.interner().fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_fn_trait_candidates(self, goal, kind) } else if let Some(kind) = self.interner().async_fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_async_fn_trait_candidates(self, goal, kind) - } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncFnKindHelper) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncFnKindHelper) { G::consider_builtin_async_fn_kind_helper_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::Tuple) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Tuple) { G::consider_builtin_tuple_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::PointeeTrait) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::PointeeTrait) { G::consider_builtin_pointee_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::Future) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Future) { G::consider_builtin_future_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::Iterator) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Iterator) { G::consider_builtin_iterator_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::FusedIterator) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::FusedIterator) { G::consider_builtin_fused_iterator_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncIterator) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncIterator) { G::consider_builtin_async_iterator_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::Coroutine) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Coroutine) { G::consider_builtin_coroutine_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::DiscriminantKind) { G::consider_builtin_discriminant_kind_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncDestruct) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncDestruct) { G::consider_builtin_async_destruct_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::Destruct) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Destruct) { G::consider_builtin_destruct_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::TransmuteTrait) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::TransmuteTrait) { G::consider_builtin_transmute_candidate(self, goal) } else { Err(NoSolution) @@ -545,18 +430,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // There may be multiple unsize candidates for a trait with several supertraits: // `trait Foo: Bar + Bar` and `dyn Foo: Unsize>` - if tcx.is_lang_item(trait_def_id, LangItem::Unsize) { + if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Unsize) { candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal)); } } #[instrument(level = "trace", skip_all)] - fn assemble_param_env_candidates>( + fn assemble_param_env_candidates>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, + goal: Goal, + candidates: &mut Vec>, ) { - for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() { + for (i, assumption) in goal.param_env.caller_bounds().into_iter().enumerate() { candidates.extend(G::probe_and_consider_implied_clause( self, CandidateSource::ParamEnv(i), @@ -568,10 +453,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } #[instrument(level = "trace", skip_all)] - fn assemble_alias_bound_candidates>( + fn assemble_alias_bound_candidates>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, + goal: Goal, + candidates: &mut Vec>, ) { let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| { ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates); @@ -587,13 +472,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// If so, continue searching by recursively calling after normalization. // FIXME: This may recurse infinitely, but I can't seem to trigger it without // hitting another overflow error something. Add a depth parameter needed later. - fn assemble_alias_bound_candidates_recur>( + fn assemble_alias_bound_candidates_recur>( &mut self, - self_ty: Ty<'tcx>, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, + self_ty: I::Ty, + goal: Goal, + candidates: &mut Vec>, ) { - let (kind, alias_ty) = match *self_ty.kind() { + let (kind, alias_ty) = match self_ty.kind() { ty::Bool | ty::Char | ty::Int(_) @@ -621,7 +506,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Error(_) => return, ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => { - bug!("unexpected self type for `{goal:?}`") + panic!("unexpected self type for `{goal:?}`") } ty::Infer(ty::TyVar(_)) => { @@ -638,16 +523,15 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), ty::Alias(ty::Inherent | ty::Weak, _) => { - self.interner().sess.dcx().span_delayed_bug( - DUMMY_SP, - format!("could not normalize {self_ty}, it is not WF"), - ); + self.interner().delay_bug(format!("could not normalize {self_ty:?}, it is not WF")); return; } }; - for assumption in - self.interner().item_bounds(alias_ty.def_id).instantiate(self.interner(), alias_ty.args) + for assumption in self + .interner() + .item_bounds(alias_ty.def_id) + .iter_instantiated(self.interner(), &alias_ty.args) { candidates.extend(G::probe_and_consider_implied_clause( self, @@ -672,18 +556,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } #[instrument(level = "trace", skip_all)] - fn assemble_object_bound_candidates>( + fn assemble_object_bound_candidates>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, + goal: Goal, + candidates: &mut Vec>, ) { let tcx = self.interner(); - if !tcx.trait_def(goal.predicate.trait_def_id(tcx)).implement_via_object { + if !tcx.trait_may_be_implemented_via_object(goal.predicate.trait_def_id(tcx)) { return; } let self_ty = goal.predicate.self_ty(); - let bounds = match *self_ty.kind() { + let bounds = match self_ty.kind() { ty::Bool | ty::Char | ty::Int(_) @@ -711,12 +595,12 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Error(_) => return, ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) - | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), + | ty::Bound(..) => panic!("unexpected self type for `{goal:?}`"), ty::Dynamic(bounds, ..) => bounds, }; // Do not consider built-in object impls for non-object-safe types. - if bounds.principal_def_id().is_some_and(|def_id| !tcx.is_object_safe(def_id)) { + if bounds.principal_def_id().is_some_and(|def_id| !tcx.trait_is_object_safe(def_id)) { return; } @@ -745,7 +629,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // a projection goal. if let Some(principal) = bounds.principal() { let principal_trait_ref = principal.with_self_ty(tcx, self_ty); - for (idx, assumption) in supertraits(self.interner(), principal_trait_ref).enumerate() { + for (idx, assumption) in + Infcx::elaborate_supertraits(tcx, principal_trait_ref).enumerate() + { candidates.extend(G::probe_and_consider_object_bound_candidate( self, CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)), @@ -763,10 +649,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// To do so we add an ambiguous candidate in case such an unknown impl could /// apply to the current goal. #[instrument(level = "trace", skip_all)] - fn assemble_coherence_unknowable_candidates>( + fn assemble_coherence_unknowable_candidates>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, + goal: Goal, + candidates: &mut Vec>, ) { let tcx = self.interner(); @@ -792,13 +678,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // to improve this however. However, this should make it fairly straightforward to refine // the filtering going forward, so it seems alright-ish for now. #[instrument(level = "debug", skip(self, goal))] - fn discard_impls_shadowed_by_env>( + fn discard_impls_shadowed_by_env>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, + goal: Goal, + candidates: &mut Vec>, ) { let tcx = self.interner(); - let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> = + let trait_goal: Goal> = goal.with(tcx, goal.predicate.trait_ref(tcx)); let mut trait_candidates_from_env = vec![]; @@ -823,7 +709,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { false } CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => true, - CandidateSource::CoherenceUnknowable => bug!("uh oh"), + CandidateSource::CoherenceUnknowable => panic!("uh oh"), }); } // If it is still ambiguous we instead just force the whole goal @@ -841,10 +727,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// to somehow try to merge the candidates into one. If that fails, we return /// ambiguity. #[instrument(level = "debug", skip(self), ret)] - pub(super) fn merge_candidates( - &mut self, - candidates: Vec>>, - ) -> QueryResult<'tcx> { + pub(super) fn merge_candidates(&mut self, candidates: Vec>) -> QueryResult { // First try merging all candidates. This is complete and fully sound. let responses = candidates.iter().map(|c| c.result).collect::>(); if let Some(result) = self.try_merge_responses(&responses) { diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs similarity index 97% rename from compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs rename to compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index d6074617cafe..202af76565a8 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -3,26 +3,24 @@ use rustc_ast_ir::{Movability, Mutability}; use rustc_data_structures::fx::FxHashMap; -use rustc_next_trait_solver::solve::{Goal, NoSolution}; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; -use rustc_type_ir::{self as ty, InferCtxtLike, Interner, Upcast}; +use rustc_type_ir::{self as ty, Interner, Upcast as _}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; +use tracing::instrument; -use crate::solve::EvalCtxt; +use crate::infcx::SolverDelegate; +use crate::solve::{EvalCtxt, Goal, NoSolution}; // Calculates the constituent types of a type for `auto trait` purposes. -// -// For types with an "existential" binder, i.e. coroutine witnesses, we also -// instantiate the binder with placeholders eagerly. #[instrument(level = "trace", skip(ecx), ret)] pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait( ecx: &EvalCtxt<'_, Infcx>, ty: I::Ty, ) -> Result>, NoSolution> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { let tcx = ecx.interner(); @@ -108,7 +106,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait( ty: I::Ty, ) -> Result>, NoSolution> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { match ty.kind() { @@ -176,7 +174,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait Result>, NoSolution> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { match ty.kind() { @@ -663,7 +661,7 @@ pub(in crate::solve) fn predicates_for_object_candidate( object_bounds: I::BoundExistentialPredicates, ) -> Vec> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { let tcx = ecx.interner(); @@ -712,14 +710,14 @@ where .collect() } -struct ReplaceProjectionWith<'a, Infcx: InferCtxtLike, I: Interner> { +struct ReplaceProjectionWith<'a, Infcx: SolverDelegate, I: Interner> { ecx: &'a EvalCtxt<'a, Infcx>, param_env: I::ParamEnv, mapping: FxHashMap>>, nested: Vec>, } -impl, I: Interner> TypeFolder +impl, I: Interner> TypeFolder for ReplaceProjectionWith<'_, Infcx, I> { fn interner(&self) -> I { @@ -744,7 +742,7 @@ impl, I: Interner> TypeFolder ) .expect("expected to be able to unify goal projection with dyn's projection"), ); - proj.term.expect_type() + proj.term.expect_ty() } else { ty.super_fold_with(self) } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs similarity index 65% rename from compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs rename to compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index b5753d60f599..c6611285a3be 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -8,58 +8,53 @@ //! section of the [rustc-dev-guide][c]. //! //! [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html -use super::{CanonicalInput, Certainty, EvalCtxt, Goal}; -use crate::solve::eval_ctxt::NestedGoals; -use crate::solve::{ - inspect, response_no_constraints_raw, CanonicalResponse, QueryResult, Response, -}; -use rustc_data_structures::fx::FxHashSet; -use rustc_index::IndexVec; -use rustc_infer::infer::canonical::query_response::make_query_region_constraints; -use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; -use rustc_infer::infer::RegionVariableOrigin; -use rustc_infer::infer::{InferCtxt, InferOk}; -use rustc_infer::traits::solve::NestedNormalizationGoals; -use rustc_middle::bug; -use rustc_middle::infer::canonical::Canonical; -use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::solve::{ - ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput, -}; -use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable}; -use rustc_next_trait_solver::canonicalizer::{CanonicalizeMode, Canonicalizer}; -use rustc_next_trait_solver::resolve::EagerResolver; -use rustc_span::{Span, DUMMY_SP}; -use rustc_type_ir::CanonicalVarValues; -use rustc_type_ir::{InferCtxtLike, Interner}; -use std::assert_matches::assert_matches; + use std::iter; -use std::ops::Deref; -trait ResponseT<'tcx> { - fn var_values(&self) -> CanonicalVarValues>; +use rustc_index::IndexVec; +use rustc_type_ir::fold::TypeFoldable; +use rustc_type_ir::inherent::*; +use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, Interner}; +use tracing::{instrument, trace}; + +use crate::canonicalizer::{CanonicalizeMode, Canonicalizer}; +use crate::infcx::SolverDelegate; +use crate::resolve::EagerResolver; +use crate::solve::eval_ctxt::NestedGoals; +use crate::solve::inspect; +use crate::solve::{ + response_no_constraints_raw, CanonicalInput, CanonicalResponse, Certainty, EvalCtxt, + ExternalConstraintsData, Goal, MaybeCause, NestedNormalizationGoals, NoSolution, + PredefinedOpaquesData, QueryInput, QueryResult, Response, +}; + +trait ResponseT { + fn var_values(&self) -> CanonicalVarValues; } -impl<'tcx> ResponseT<'tcx> for Response> { - fn var_values(&self) -> CanonicalVarValues> { +impl ResponseT for Response { + fn var_values(&self) -> CanonicalVarValues { self.var_values } } -impl<'tcx, T> ResponseT<'tcx> for inspect::State, T> { - fn var_values(&self) -> CanonicalVarValues> { +impl ResponseT for inspect::State { + fn var_values(&self) -> CanonicalVarValues { self.var_values } } -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +impl EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ /// Canonicalizes the goal remembering the original values /// for each bound variable. - pub(super) fn canonicalize_goal>>( + pub(super) fn canonicalize_goal>( &self, - goal: Goal<'tcx, T>, - ) -> (Vec>, CanonicalInput<'tcx, T>) { + goal: Goal, + ) -> (Vec, CanonicalInput) { let opaque_types = self.infcx.clone_opaque_types_for_query_response(); let (goal, opaque_types) = (goal, opaque_types).fold_with(&mut EagerResolver::new(self.infcx)); @@ -89,7 +84,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response( &mut self, certainty: Certainty, - ) -> QueryResult<'tcx> { + ) -> QueryResult { self.inspect.make_canonical_response(certainty); let goals_certainty = self.try_evaluate_added_goals()?; @@ -102,8 +97,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // We only check for leaks from universes which were entered inside // of the query. - self.infcx.leak_check(self.max_input_universe, None).map_err(|e| { - trace!(?e, "failed the leak check"); + self.infcx.leak_check(self.max_input_universe).map_err(|NoSolution| { + trace!("failed the leak check"); NoSolution })?; @@ -119,7 +114,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { if cfg!(debug_assertions) { assert!(normalizes_to_goals.is_empty()); if goals.is_empty() { - assert_matches!(goals_certainty, Certainty::Yes); + assert!(matches!(goals_certainty, Certainty::Yes)); } } (certainty, NestedNormalizationGoals(goals)) @@ -158,7 +153,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(in crate::solve) fn make_ambiguous_response_no_constraints( &self, maybe_cause: MaybeCause, - ) -> CanonicalResponse<'tcx> { + ) -> CanonicalResponse { response_no_constraints_raw( self.interner(), self.max_input_universe, @@ -178,8 +173,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn compute_external_query_constraints( &self, certainty: Certainty, - normalization_nested_goals: NestedNormalizationGoals>, - ) -> ExternalConstraintsData> { + normalization_nested_goals: NestedNormalizationGoals, + ) -> ExternalConstraintsData { // We only return region constraints once the certainty is `Yes`. This // is necessary as we may drop nested goals on ambiguity, which may result // in unconstrained inference variables in the region constraints. It also @@ -189,26 +184,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs` and // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`. let region_constraints = if certainty == Certainty::Yes { - // Cannot use `take_registered_region_obligations` as we may compute the response - // inside of a `probe` whenever we have multiple choices inside of the solver. - let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); - let QueryRegionConstraints { outlives, member_constraints } = - self.infcx.with_region_constraints(|region_constraints| { - make_query_region_constraints( - self.interner(), - region_obligations.iter().map(|r_o| { - (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category()) - }), - region_constraints, - ) - }); - assert_eq!(member_constraints, vec![]); - let mut seen = FxHashSet::default(); - outlives - .into_iter() - .filter(|(outlives, _)| seen.insert(*outlives)) - .map(|(outlives, _origin)| outlives) - .collect() + self.infcx.make_deduplicated_outlives_constraints() } else { Default::default() }; @@ -238,10 +214,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// the `normalization_nested_goals` pub(super) fn instantiate_and_apply_query_response( &mut self, - param_env: ty::ParamEnv<'tcx>, - original_values: Vec>, - response: CanonicalResponse<'tcx>, - ) -> (NestedNormalizationGoals>, Certainty) { + param_env: I::ParamEnv, + original_values: Vec, + response: CanonicalResponse, + ) -> (NestedNormalizationGoals, Certainty) { let instantiation = Self::compute_query_response_instantiation_values( self.infcx, &original_values, @@ -249,7 +225,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ); let Response { var_values, external_constraints, certainty } = - response.instantiate(self.interner(), &instantiation); + self.infcx.instantiate_canonical(response, instantiation); Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values); @@ -257,7 +233,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { region_constraints, opaque_types, normalization_nested_goals, - } = external_constraints.deref(); + } = &*external_constraints; self.register_region_constraints(region_constraints); self.register_new_opaque_types(opaque_types); (normalization_nested_goals.clone(), certainty) @@ -266,11 +242,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// This returns the canoncial variable values to instantiate the bound variables of /// the canonical response. This depends on the `original_values` for the /// bound variables. - fn compute_query_response_instantiation_values>( - infcx: &InferCtxt<'tcx>, - original_values: &[ty::GenericArg<'tcx>], - response: &Canonical<'tcx, T>, - ) -> CanonicalVarValues> { + fn compute_query_response_instantiation_values>( + infcx: &Infcx, + original_values: &[I::GenericArg], + response: &Canonical, + ) -> CanonicalVarValues { // FIXME: Longterm canonical queries should deal with all placeholders // created inside of the query directly instead of returning them to the // caller. @@ -292,35 +268,35 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // inference variable of the input right away, which is more performant. let mut opt_values = IndexVec::from_elem_n(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() { + match result_value.kind() { + ty::GenericArgKind::Type(t) => { + if let ty::Bound(debruijn, b) = t.kind() { assert_eq!(debruijn, ty::INNERMOST); - opt_values[b.var] = Some(*original_value); + opt_values[b.var()] = Some(*original_value); } } - GenericArgKind::Lifetime(r) => { - if let ty::ReBound(debruijn, br) = *r { + ty::GenericArgKind::Lifetime(r) => { + if let ty::ReBound(debruijn, br) = r.kind() { assert_eq!(debruijn, ty::INNERMOST); - opt_values[br.var] = Some(*original_value); + opt_values[br.var()] = Some(*original_value); } } - GenericArgKind::Const(c) => { - if let ty::ConstKind::Bound(debruijn, b) = c.kind() { + ty::GenericArgKind::Const(c) => { + if let ty::ConstKind::Bound(debruijn, bv) = c.kind() { assert_eq!(debruijn, ty::INNERMOST); - opt_values[b] = Some(*original_value); + opt_values[bv.var()] = Some(*original_value); } } } } - let var_values = infcx.tcx.mk_args_from_iter(response.variables.iter().enumerate().map( - |(index, info)| { + let var_values = infcx.interner().mk_args_from_iter( + response.variables.into_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. - infcx.instantiate_canonical_var(DUMMY_SP, info, |idx| { + infcx.instantiate_canonical_var_with_infer(info, |idx| { ty::UniverseIndex::from(prev_universe.index() + idx.index()) }) } else if info.is_existential() { @@ -331,18 +307,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // 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[BoundVar::from_usize(index)] { + if let Some(v) = opt_values[ty::BoundVar::from_usize(index)] { v } else { - infcx.instantiate_canonical_var(DUMMY_SP, info, |_| prev_universe) + infcx.instantiate_canonical_var_with_infer(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_placeholder_index()] } - }, - )); + }), + ); CanonicalVarValues { var_values } } @@ -361,40 +337,35 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// always relate them structurally here. #[instrument(level = "trace", skip(infcx))] fn unify_query_var_values( - infcx: &InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - original_values: &[ty::GenericArg<'tcx>], - var_values: CanonicalVarValues>, + infcx: &Infcx, + param_env: I::ParamEnv, + original_values: &[I::GenericArg], + var_values: CanonicalVarValues, ) { assert_eq!(original_values.len(), var_values.len()); - let cause = ObligationCause::dummy(); for (&orig, response) in iter::zip(original_values, var_values.var_values) { - let InferOk { value: (), obligations } = infcx - .at(&cause, param_env) - .eq_structurally_relating_aliases(orig, response) - .unwrap(); - assert!(obligations.is_empty()); + let goals = infcx.eq_structurally_relating_aliases(param_env, orig, response).unwrap(); + assert!(goals.is_empty()); } } fn register_region_constraints( &mut self, - outlives: &[ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>], + outlives: &[ty::OutlivesPredicate], ) { for &ty::OutlivesPredicate(lhs, rhs) in outlives { - match lhs.unpack() { - GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs), - GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs), - GenericArgKind::Const(_) => bug!("const outlives: {lhs:?}: {rhs:?}"), + match lhs.kind() { + ty::GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs), + ty::GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs), + ty::GenericArgKind::Const(_) => panic!("const outlives: {lhs:?}: {rhs:?}"), } } } - fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)]) { + fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey, I::Ty)]) { for &(key, ty) in opaque_types { - let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP }; - self.infcx.inject_new_hidden_type_unchecked(key, hidden_ty); + self.infcx.inject_new_hidden_type_unchecked(key, ty); } } } @@ -410,7 +381,7 @@ pub(in crate::solve) fn make_canonical_state( data: T, ) -> inspect::CanonicalState where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, T: TypeFoldable, { @@ -425,45 +396,33 @@ where ) } -/// Instantiate a `CanonicalState`. -/// -/// Unlike for query responses, `CanonicalState` also track fresh inference -/// variables created while evaluating a goal. When creating two separate -/// `CanonicalState` during a single evaluation both may reference this -/// fresh inference variable. When instantiating them we now create separate -/// inference variables for it and have to unify them somehow. We do this -/// by extending the `var_values` while building the proof tree. -/// -/// This currently assumes that unifying the var values trivially succeeds. -/// Adding any inference constraints which weren't present when originally -/// computing the canonical query can result in bugs. -#[instrument(level = "trace", skip(infcx, span, param_env))] -pub(in crate::solve) fn instantiate_canonical_state<'tcx, T: TypeFoldable>>( - infcx: &InferCtxt<'tcx>, - span: Span, - param_env: ty::ParamEnv<'tcx>, - orig_values: &mut Vec>, - state: inspect::CanonicalState, T>, -) -> T { +// FIXME: needs to be pub to be accessed by downstream +// `rustc_trait_selection::solve::inspect::analyse`. +pub fn instantiate_canonical_state>( + infcx: &Infcx, + span: Infcx::Span, + param_env: I::ParamEnv, + orig_values: &mut Vec, + state: inspect::CanonicalState, +) -> T +where + Infcx: SolverDelegate, + I: Interner, +{ // In case any fresh inference variables have been created between `state` // and the previous instantiation, extend `orig_values` for it. assert!(orig_values.len() <= state.value.var_values.len()); - for i in orig_values.len()..state.value.var_values.len() { - let unconstrained = match state.value.var_values.var_values[i].unpack() { - ty::GenericArgKind::Lifetime(_) => { - infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)).into() - } - ty::GenericArgKind::Type(_) => infcx.next_ty_var(span).into(), - ty::GenericArgKind::Const(_) => infcx.next_const_var(span).into(), - }; - + for &arg in &state.value.var_values.var_values[orig_values.len()..state.value.var_values.len()] + { + // FIXME: This is so ugly. + let unconstrained = infcx.fresh_var_for_kind_with_span(arg, span); orig_values.push(unconstrained); } let instantiation = EvalCtxt::compute_query_response_instantiation_values(infcx, orig_values, &state); - let inspect::State { var_values, data } = state.instantiate(infcx.tcx, &instantiation); + let inspect::State { var_values, data } = infcx.instantiate_canonical(state, instantiation); EvalCtxt::unify_query_var_values(infcx, param_env, orig_values, var_values); data diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs similarity index 78% rename from compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs rename to compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 74938d2bbd70..485758b91a28 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1,41 +1,30 @@ -use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_hir::def_id::DefId; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::query::NoSolution; -use rustc_infer::traits::solve::{MaybeCause, NestedNormalizationGoals}; -use rustc_infer::traits::ObligationCause; -use rustc_macros::{extension, HashStable, HashStable_NoContext, TyDecodable, TyEncodable}; -use rustc_middle::bug; -use rustc_middle::traits::solve::{ - inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaquesData, QueryResult, -}; -use rustc_middle::ty::AliasRelationDirection; -use rustc_middle::ty::TypeFolder; -use rustc_middle::ty::{ - self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, -}; -use rustc_span::DUMMY_SP; -use rustc_type_ir::fold::TypeSuperFoldable; -use rustc_type_ir::inherent::*; -use rustc_type_ir::relate::Relate; -use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use rustc_type_ir::{self as ir, CanonicalVarValues, Interner}; -use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use std::ops::ControlFlow; -use crate::traits::coherence; +use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_type_ir::inherent::*; +use rustc_type_ir::relate::Relate; +use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; +use rustc_type_ir::{self as ty, CanonicalVarValues, Interner}; +use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; +use tracing::{instrument, trace}; -use super::inspect::ProofTreeBuilder; -use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT}; -use super::{search_graph::SearchGraph, Goal}; -use super::{GoalSource, SolverMode}; +use crate::infcx::SolverDelegate; +use crate::solve::inspect::{self, ProofTreeBuilder}; +use crate::solve::search_graph::SearchGraph; +use crate::solve::{ + search_graph, CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind, + GoalSource, MaybeCause, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, + QueryResult, SolverMode, FIXPOINT_STEP_LIMIT, +}; pub(super) mod canonical; mod probe; -pub struct EvalCtxt<'a, Infcx, I = ::Interner> +pub struct EvalCtxt<'a, Infcx, I = ::Interner> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { /// The inference context that backs (mostly) inference and placeholder terms @@ -112,9 +101,9 @@ pub struct NestedGoals { /// /// Forgetting to replace the RHS with a fresh inference variable when we evaluate /// this goal results in an ICE.. - pub normalizes_to_goals: Vec>>, + pub normalizes_to_goals: Vec>>, /// The rest of the goals which have not yet processed or remain ambiguous. - pub goals: Vec<(GoalSource, ir::solve::Goal)>, + pub goals: Vec<(GoalSource, Goal)>, } impl NestedGoals { @@ -127,14 +116,36 @@ impl NestedGoals { } } -#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)] +#[derive(PartialEq, Eq, Debug, Hash, HashStable_NoContext, Clone, Copy)] pub enum GenerateProofTree { Yes, No, } -#[extension(pub trait InferCtxtEvalExt<'tcx>)] -impl<'tcx> InferCtxt<'tcx> { +pub trait SolverDelegateEvalExt: SolverDelegate { + fn evaluate_root_goal( + &self, + goal: Goal::Predicate>, + generate_proof_tree: GenerateProofTree, + ) -> (Result<(bool, Certainty), NoSolution>, Option>); + + // FIXME: This is only exposed because we need to use it in `analyse.rs` + // which is not yet uplifted. Once that's done, we should remove this. + fn evaluate_root_goal_raw( + &self, + goal: Goal::Predicate>, + generate_proof_tree: GenerateProofTree, + ) -> ( + Result<(NestedNormalizationGoals, bool, Certainty), NoSolution>, + Option>, + ); +} + +impl SolverDelegateEvalExt for Infcx +where + Infcx: SolverDelegate, + I: Interner, +{ /// Evaluates a goal from **outside** of the trait solver. /// /// Using this while inside of the solver is wrong as it uses a new @@ -142,17 +153,34 @@ impl<'tcx> InferCtxt<'tcx> { #[instrument(level = "debug", skip(self))] fn evaluate_root_goal( &self, - goal: Goal<'tcx, ty::Predicate<'tcx>>, + goal: Goal, generate_proof_tree: GenerateProofTree, - ) -> (Result<(bool, Certainty), NoSolution>, Option>>) - { + ) -> (Result<(bool, Certainty), NoSolution>, Option>) { EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal) }) } + + #[instrument(level = "debug", skip(self))] + fn evaluate_root_goal_raw( + &self, + goal: Goal, + generate_proof_tree: GenerateProofTree, + ) -> ( + Result<(NestedNormalizationGoals, bool, Certainty), NoSolution>, + Option>, + ) { + EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { + ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal) + }) + } } -impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { +impl<'a, Infcx, I> EvalCtxt<'a, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ pub(super) fn solver_mode(&self) -> SolverMode { self.search_graph.solver_mode() } @@ -163,14 +191,13 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { /// Creates a root evaluation context and search graph. This should only be /// used from outside of any evaluation, and other methods should be preferred - /// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]). + /// over using this manually (such as [`SolverDelegateEvalExt::evaluate_root_goal`]). pub(super) fn enter_root( - infcx: &InferCtxt<'tcx>, + infcx: &Infcx, generate_proof_tree: GenerateProofTree, - f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> R, - ) -> (R, Option>>) { - let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal }; - let mut search_graph = search_graph::SearchGraph::new(mode); + f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> R, + ) -> (R, Option>) { + let mut search_graph = search_graph::SearchGraph::new(infcx.solver_mode()); let mut ecx = EvalCtxt { infcx, @@ -181,10 +208,10 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { // Only relevant when canonicalizing the response, // which we don't do within this evaluation context. predefined_opaques_in_body: infcx - .tcx + .interner() .mk_predefined_opaques_in_body(PredefinedOpaquesData::default()), max_input_universe: ty::UniverseIndex::ROOT, - variables: ty::List::empty(), + variables: Default::default(), var_values: CanonicalVarValues::dummy(), is_normalizes_to_goal: false, tainted: Ok(()), @@ -210,21 +237,14 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { /// This function takes care of setting up the inference context, setting the anchor, /// and registering opaques from the canonicalized input. fn enter_canonical( - tcx: TyCtxt<'tcx>, - search_graph: &'a mut search_graph::SearchGraph>, - canonical_input: CanonicalInput<'tcx>, - canonical_goal_evaluation: &mut ProofTreeBuilder>, - f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>, Goal<'tcx, ty::Predicate<'tcx>>) -> R, + tcx: I, + search_graph: &'a mut search_graph::SearchGraph, + canonical_input: CanonicalInput, + canonical_goal_evaluation: &mut ProofTreeBuilder, + f: impl FnOnce(&mut EvalCtxt<'_, Infcx>, Goal) -> R, ) -> R { - let intercrate = match search_graph.solver_mode() { - SolverMode::Normal => false, - SolverMode::Coherence => true, - }; - let (ref infcx, input, var_values) = tcx - .infer_ctxt() - .intercrate(intercrate) - .with_next_trait_solver(true) - .build_with_canonical(DUMMY_SP, &canonical_input); + let (ref infcx, input, var_values) = + SolverDelegate::build_with_canonical(tcx, search_graph.solver_mode(), &canonical_input); let mut ecx = EvalCtxt { infcx, @@ -240,8 +260,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { }; for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { - let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP }; - ecx.infcx.inject_new_hidden_type_unchecked(key, hidden_ty); + ecx.infcx.inject_new_hidden_type_unchecked(key, ty); } if !ecx.nested_goals.is_empty() { @@ -256,7 +275,8 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { // instead of taking them. This would cause an ICE here, since we have // assertions against dropping an `InferCtxt` without taking opaques. // FIXME: Once we remove support for the old impl we can remove this. - let _ = infcx.take_opaque_types(); + // FIXME: Could we make `build_with_canonical` into `enter_with_canonical` and call this at the end? + infcx.reset_opaque_types(); result } @@ -268,15 +288,15 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { /// logic of the solver. /// /// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal] - /// if you're inside of the solver or [InferCtxtEvalExt::evaluate_root_goal] if you're + /// if you're inside of the solver or [SolverDelegateEvalExt::evaluate_root_goal] if you're /// outside of it. #[instrument(level = "debug", skip(tcx, search_graph, goal_evaluation), ret)] fn evaluate_canonical_goal( - tcx: TyCtxt<'tcx>, - search_graph: &'a mut search_graph::SearchGraph>, - canonical_input: CanonicalInput<'tcx>, - goal_evaluation: &mut ProofTreeBuilder>, - ) -> QueryResult<'tcx> { + tcx: I, + search_graph: &'a mut search_graph::SearchGraph, + canonical_input: CanonicalInput, + goal_evaluation: &mut ProofTreeBuilder, + ) -> QueryResult { let mut canonical_goal_evaluation = goal_evaluation.new_canonical_goal_evaluation(canonical_input); @@ -315,7 +335,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { &mut self, goal_evaluation_kind: GoalEvaluationKind, source: GoalSource, - goal: Goal<'tcx, ty::Predicate<'tcx>>, + goal: Goal, ) -> Result<(bool, Certainty), NoSolution> { let (normalization_nested_goals, has_changed, certainty) = self.evaluate_goal_raw(goal_evaluation_kind, source, goal)?; @@ -336,8 +356,8 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { &mut self, goal_evaluation_kind: GoalEvaluationKind, _source: GoalSource, - goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(NestedNormalizationGoals>, bool, Certainty), NoSolution> { + goal: Goal, + ) -> Result<(NestedNormalizationGoals, bool, Certainty), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); @@ -377,10 +397,10 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { fn instantiate_response_discarding_overflow( &mut self, - param_env: ty::ParamEnv<'tcx>, - original_values: Vec>, - response: CanonicalResponse<'tcx>, - ) -> (NestedNormalizationGoals>, Certainty, bool) { + param_env: I::ParamEnv, + original_values: Vec, + response: CanonicalResponse, + ) -> (NestedNormalizationGoals, Certainty, bool) { if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty { return (NestedNormalizationGoals::empty(), response.value.certainty, false); } @@ -393,7 +413,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { (normalization_nested_goals, certainty, has_changed) } - fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> { + fn compute_goal(&mut self, goal: Goal) -> QueryResult { let Goal { param_env, predicate } = goal; let kind = predicate.kind(); if let Some(kind) = kind.no_bound_vars() { @@ -429,7 +449,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { self.compute_const_evaluatable_goal(Goal { param_env, predicate: ct }) } ty::PredicateKind::ConstEquate(_, _) => { - bug!("ConstEquate should not be emitted when `-Znext-solver` is active") + panic!("ConstEquate should not be emitted when `-Znext-solver` is active") } ty::PredicateKind::NormalizesTo(predicate) => { self.compute_normalizes_to_goal(Goal { param_env, predicate }) @@ -565,21 +585,16 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } /// Record impl args in the proof tree for later access by `InspectCandidate`. - pub(crate) fn record_impl_args(&mut self, impl_args: ty::GenericArgsRef<'tcx>) { + pub(crate) fn record_impl_args(&mut self, impl_args: I::GenericArgs) { self.inspect.record_impl_args(self.infcx, self.max_input_universe, impl_args) } -} -impl, I: Interner> EvalCtxt<'_, Infcx> { pub(super) fn interner(&self) -> I { self.infcx.interner() } #[instrument(level = "trace", skip(self))] - pub(super) fn add_normalizes_to_goal( - &mut self, - mut goal: ir::solve::Goal>, - ) { + pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal>) { goal.predicate = goal .predicate .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); @@ -588,11 +603,7 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { } #[instrument(level = "debug", skip(self))] - pub(super) fn add_goal( - &mut self, - source: GoalSource, - mut goal: ir::solve::Goal, - ) { + pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal) { goal.predicate = goal .predicate .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); @@ -604,7 +615,7 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { pub(super) fn add_goals( &mut self, source: GoalSource, - goals: impl IntoIterator>, + goals: impl IntoIterator>, ) { for goal in goals { self.add_goal(source, goal); @@ -627,8 +638,8 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { /// If `kind` is an integer inference variable this will still return a ty infer var. pub(super) fn next_term_infer_of_kind(&mut self, kind: I::Term) -> I::Term { match kind.kind() { - ir::TermKind::Ty(_) => self.next_ty_infer().into(), - ir::TermKind::Const(_) => self.next_const_infer().into(), + ty::TermKind::Ty(_) => self.next_ty_infer().into(), + ty::TermKind::Const(_) => self.next_const_infer().into(), } } @@ -637,20 +648,17 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { /// This is the case if the `term` does not occur in any other part of the predicate /// and is able to name all other placeholder and inference variables. #[instrument(level = "trace", skip(self), ret)] - pub(super) fn term_is_fully_unconstrained( - &self, - goal: ir::solve::Goal>, - ) -> bool { + pub(super) fn term_is_fully_unconstrained(&self, goal: Goal>) -> bool { let universe_of_term = match goal.predicate.term.kind() { - ir::TermKind::Ty(ty) => { - if let ir::Infer(ir::TyVar(vid)) = ty.kind() { + ty::TermKind::Ty(ty) => { + if let ty::Infer(ty::TyVar(vid)) = ty.kind() { self.infcx.universe_of_ty(vid).unwrap() } else { return false; } } - ir::TermKind::Const(ct) => { - if let ir::ConstKind::Infer(ir::InferConst::Var(vid)) = ct.kind() { + ty::TermKind::Const(ct) => { + if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { self.infcx.universe_of_ct(vid).unwrap() } else { return false; @@ -658,14 +666,14 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { } }; - struct ContainsTermOrNotNameable<'a, Infcx: InferCtxtLike, I: Interner> { + struct ContainsTermOrNotNameable<'a, Infcx: SolverDelegate, I: Interner> { term: I::Term, - universe_of_term: ir::UniverseIndex, + universe_of_term: ty::UniverseIndex, infcx: &'a Infcx, } - impl, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> { - fn check_nameable(&self, universe: ir::UniverseIndex) -> ControlFlow<()> { + impl, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> { + fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> { if self.universe_of_term.can_name(universe) { ControlFlow::Continue(()) } else { @@ -674,15 +682,15 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { } } - impl, I: Interner> TypeVisitor + impl, I: Interner> TypeVisitor for ContainsTermOrNotNameable<'_, Infcx, I> { type Result = ControlFlow<()>; fn visit_ty(&mut self, t: I::Ty) -> Self::Result { match t.kind() { - ir::Infer(ir::TyVar(vid)) => { - if let ir::TermKind::Ty(term) = self.term.kind() - && let ir::Infer(ir::TyVar(term_vid)) = term.kind() + ty::Infer(ty::TyVar(vid)) => { + if let ty::TermKind::Ty(term) = self.term.kind() + && let ty::Infer(ty::TyVar(term_vid)) = term.kind() && self.infcx.root_ty_var(vid) == self.infcx.root_ty_var(term_vid) { ControlFlow::Break(()) @@ -690,7 +698,7 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { self.check_nameable(self.infcx.universe_of_ty(vid).unwrap()) } } - ir::Placeholder(p) => self.check_nameable(p.universe()), + ty::Placeholder(p) => self.check_nameable(p.universe()), _ => { if t.has_non_region_infer() || t.has_placeholders() { t.super_visit_with(self) @@ -703,9 +711,9 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { fn visit_const(&mut self, c: I::Const) -> Self::Result { match c.kind() { - ir::ConstKind::Infer(ir::InferConst::Var(vid)) => { - if let ir::TermKind::Const(term) = self.term.kind() - && let ir::ConstKind::Infer(ir::InferConst::Var(term_vid)) = term.kind() + ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { + if let ty::TermKind::Const(term) = self.term.kind() + && let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() && self.infcx.root_const_var(vid) == self.infcx.root_const_var(term_vid) { ControlFlow::Break(()) @@ -713,7 +721,7 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { self.check_nameable(self.infcx.universe_of_ct(vid).unwrap()) } } - ir::ConstKind::Placeholder(p) => self.check_nameable(p.universe()), + ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe()), _ => { if c.has_non_region_infer() || c.has_placeholders() { c.super_visit_with(self) @@ -741,7 +749,7 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { lhs: T, rhs: T, ) -> Result<(), NoSolution> { - self.relate(param_env, lhs, ir::Variance::Invariant, rhs) + self.relate(param_env, lhs, ty::Variance::Invariant, rhs) } /// This should be used when relating a rigid alias with another type. @@ -753,8 +761,8 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { pub(super) fn relate_rigid_alias_non_alias( &mut self, param_env: I::ParamEnv, - alias: ir::AliasTerm, - variance: ir::Variance, + alias: ty::AliasTerm, + variance: ty::Variance, term: I::Term, ) -> Result<(), NoSolution> { // NOTE: this check is purely an optimization, the structural eq would @@ -770,7 +778,7 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { // Alternatively we could modify `Equate` for this case by adding another // variant to `StructurallyRelateAliases`. let identity_args = self.fresh_args_for_item(alias.def_id); - let rigid_ctor = ir::AliasTerm::new(tcx, alias.def_id, identity_args); + let rigid_ctor = ty::AliasTerm::new(tcx, alias.def_id, identity_args); let ctor_term = rigid_ctor.to_term(tcx); let obligations = self.infcx.eq_structurally_relating_aliases(param_env, term, ctor_term)?; @@ -803,7 +811,7 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { sub: T, sup: T, ) -> Result<(), NoSolution> { - self.relate(param_env, sub, ir::Variance::Covariant, sup) + self.relate(param_env, sub, ty::Variance::Covariant, sup) } #[instrument(level = "trace", skip(self, param_env), ret)] @@ -811,7 +819,7 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { &mut self, param_env: I::ParamEnv, lhs: T, - variance: ir::Variance, + variance: ty::Variance, rhs: T, ) -> Result<(), NoSolution> { let goals = self.infcx.relate(param_env, lhs, variance, rhs)?; @@ -830,20 +838,20 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { param_env: I::ParamEnv, lhs: T, rhs: T, - ) -> Result>, NoSolution> { - self.infcx.relate(param_env, lhs, ir::Variance::Invariant, rhs) + ) -> Result>, NoSolution> { + self.infcx.relate(param_env, lhs, ty::Variance::Invariant, rhs) } pub(super) fn instantiate_binder_with_infer + Copy>( &self, - value: ir::Binder, + value: ty::Binder, ) -> T { self.infcx.instantiate_binder_with_infer(value) } pub(super) fn enter_forall + Copy, U>( &self, - value: ir::Binder, + value: ty::Binder, f: impl FnOnce(T) -> U, ) -> U { self.infcx.enter_forall(value, f) @@ -863,89 +871,72 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { } args } -} -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { - pub(super) fn register_ty_outlives(&self, ty: Ty<'tcx>, lt: ty::Region<'tcx>) { - self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy()); + pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region) { + self.infcx.register_ty_outlives(ty, lt); } - pub(super) fn register_region_outlives(&self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) { + pub(super) fn register_region_outlives(&self, a: I::Region, b: I::Region) { // `b : a` ==> `a <= b` - // (inlined from `InferCtxt::region_outlives_predicate`) - self.infcx.sub_regions( - rustc_infer::infer::SubregionOrigin::RelateRegionParamBound(DUMMY_SP), - b, - a, - ); + self.infcx.sub_regions(b, a); } /// Computes the list of goals required for `arg` to be well-formed pub(super) fn well_formed_goals( &self, - param_env: ty::ParamEnv<'tcx>, - arg: ty::GenericArg<'tcx>, - ) -> Option>>> { - crate::traits::wf::unnormalized_obligations(self.infcx, param_env, arg) - .map(|obligations| obligations.into_iter().map(|obligation| obligation.into())) - } - - pub(super) fn is_transmutable( - &self, - src_and_dst: rustc_transmute::Types<'tcx>, - assume: rustc_transmute::Assume, - ) -> Result { - use rustc_transmute::Answer; - // FIXME(transmutability): This really should be returning nested goals for `Answer::If*` - match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( - ObligationCause::dummy(), - src_and_dst, - assume, - ) { - Answer::Yes => Ok(Certainty::Yes), - Answer::No(_) | Answer::If(_) => Err(NoSolution), - } + param_env: I::ParamEnv, + arg: I::GenericArg, + ) -> Option>> { + self.infcx.well_formed_goals(param_env, arg) } pub(super) fn trait_ref_is_knowable( &mut self, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::TraitRef<'tcx>, + param_env: I::ParamEnv, + trait_ref: ty::TraitRef, ) -> Result { let infcx = self.infcx; let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty); - coherence::trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) - .map(|is_knowable| is_knowable.is_ok()) + infcx.trait_ref_is_knowable(trait_ref, lazily_normalize_ty) } - pub(super) fn can_define_opaque_ty(&self, def_id: impl Into) -> bool { - self.infcx.can_define_opaque_ty(def_id) + pub(super) fn fetch_eligible_assoc_item( + &self, + param_env: I::ParamEnv, + goal_trait_ref: ty::TraitRef, + trait_assoc_def_id: I::DefId, + impl_def_id: I::DefId, + ) -> Result, NoSolution> { + self.infcx.fetch_eligible_assoc_item( + param_env, + goal_trait_ref, + trait_assoc_def_id, + impl_def_id, + ) + } + + pub(super) fn can_define_opaque_ty(&self, def_id: I::LocalDefId) -> bool { + self.infcx.defining_opaque_types().contains(&def_id) } pub(super) fn insert_hidden_type( &mut self, - opaque_type_key: OpaqueTypeKey<'tcx>, - param_env: ty::ParamEnv<'tcx>, - hidden_ty: Ty<'tcx>, + opaque_type_key: ty::OpaqueTypeKey, + param_env: I::ParamEnv, + hidden_ty: I::Ty, ) -> Result<(), NoSolution> { let mut goals = Vec::new(); - self.infcx.insert_hidden_type( - opaque_type_key, - DUMMY_SP, - param_env, - hidden_ty, - &mut goals, - )?; + self.infcx.insert_hidden_type(opaque_type_key, param_env, hidden_ty, &mut goals)?; self.add_goals(GoalSource::Misc, goals); Ok(()) } pub(super) fn add_item_bounds_for_hidden_type( &mut self, - opaque_def_id: DefId, - opaque_args: ty::GenericArgsRef<'tcx>, - param_env: ty::ParamEnv<'tcx>, - hidden_ty: Ty<'tcx>, + opaque_def_id: I::DefId, + opaque_args: I::GenericArgs, + param_env: I::ParamEnv, + hidden_ty: I::Ty, ) { let mut goals = Vec::new(); self.infcx.add_item_bounds_for_hidden_type( @@ -962,10 +953,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // current inference context. pub(super) fn unify_existing_opaque_tys( &mut self, - param_env: ty::ParamEnv<'tcx>, - key: ty::OpaqueTypeKey<'tcx>, - ty: Ty<'tcx>, - ) -> Vec> { + param_env: I::ParamEnv, + key: ty::OpaqueTypeKey, + ty: I::Ty, + ) -> Vec> { // FIXME: Super inefficient to be cloning this... let opaques = self.infcx.clone_opaque_types_for_query_response(); @@ -984,7 +975,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } ecx.eq(param_env, candidate_ty, ty)?; ecx.add_item_bounds_for_hidden_type( - candidate_key.def_id.to_def_id(), + candidate_key.def_id.into(), candidate_key.args, param_env, candidate_ty, @@ -1001,23 +992,20 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // as an ambiguity rather than no-solution. pub(super) fn try_const_eval_resolve( &self, - param_env: ty::ParamEnv<'tcx>, - unevaluated: ty::UnevaluatedConst<'tcx>, - ) -> Option> { - use rustc_middle::mir::interpret::ErrorHandled; - match self.infcx.const_eval_resolve(param_env, unevaluated, DUMMY_SP) { - Ok(Some(val)) => Some(ty::Const::new_value( - self.interner(), - val, - self.interner() - .type_of(unevaluated.def) - .instantiate(self.interner(), unevaluated.args), - )), - Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None, - Err(ErrorHandled::Reported(e, _)) => { - Some(ty::Const::new_error(self.interner(), e.into())) - } - } + param_env: I::ParamEnv, + unevaluated: ty::UnevaluatedConst, + ) -> Option { + self.infcx.try_const_eval_resolve(param_env, unevaluated) + } + + pub(super) fn is_transmutable( + &mut self, + param_env: I::ParamEnv, + dst: I::Ty, + src: I::Ty, + assume: I::Const, + ) -> Result { + self.infcx.is_transmutable(param_env, dst, src, assume) } } @@ -1030,7 +1018,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs. struct ReplaceAliasWithInfer<'me, 'a, Infcx, I> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { ecx: &'me mut EvalCtxt<'a, Infcx>, @@ -1039,7 +1027,7 @@ where impl TypeFolder for ReplaceAliasWithInfer<'_, '_, Infcx, I> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { fn interner(&self) -> I { @@ -1048,16 +1036,16 @@ where fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { match ty.kind() { - ir::Alias(..) if !ty.has_escaping_bound_vars() => { + ty::Alias(..) if !ty.has_escaping_bound_vars() => { let infer_ty = self.ecx.next_ty_infer(); - let normalizes_to = ir::PredicateKind::AliasRelate( + let normalizes_to = ty::PredicateKind::AliasRelate( ty.into(), infer_ty.into(), - AliasRelationDirection::Equate, + ty::AliasRelationDirection::Equate, ); self.ecx.add_goal( GoalSource::Misc, - ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to), + Goal::new(self.interner(), self.param_env, normalizes_to), ); infer_ty } @@ -1067,16 +1055,16 @@ where fn fold_const(&mut self, ct: I::Const) -> I::Const { match ct.kind() { - ir::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => { + ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => { let infer_ct = self.ecx.next_const_infer(); - let normalizes_to = ir::PredicateKind::AliasRelate( + let normalizes_to = ty::PredicateKind::AliasRelate( ct.into(), infer_ct.into(), - AliasRelationDirection::Equate, + ty::AliasRelationDirection::Equate, ); self.ecx.add_goal( GoalSource::Misc, - ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to), + Goal::new(self.interner(), self.param_env, normalizes_to), ); infer_ct } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs similarity index 89% rename from compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs rename to compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs index ad6fdd2707de..1c5358b3edb4 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs @@ -1,15 +1,16 @@ -use crate::solve::assembly::Candidate; - -use super::EvalCtxt; -use rustc_next_trait_solver::solve::{ - inspect, BuiltinImplSource, CandidateSource, NoSolution, QueryResult, -}; -use rustc_type_ir::{InferCtxtLike, Interner}; use std::marker::PhantomData; +use rustc_type_ir::Interner; +use tracing::instrument; + +use crate::infcx::SolverDelegate; +use crate::solve::assembly::Candidate; +use crate::solve::inspect; +use crate::solve::{BuiltinImplSource, CandidateSource, EvalCtxt, NoSolution, QueryResult}; + pub(in crate::solve) struct ProbeCtxt<'me, 'a, Infcx, I, F, T> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { ecx: &'me mut EvalCtxt<'a, Infcx, I>, @@ -20,7 +21,7 @@ where impl ProbeCtxt<'_, '_, Infcx, I, F, T> where F: FnOnce(&T) -> inspect::ProbeKind, - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> T) -> T { @@ -56,7 +57,7 @@ where pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, Infcx, I, F> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { cx: ProbeCtxt<'me, 'a, Infcx, I, F, QueryResult>, @@ -65,7 +66,7 @@ where impl TraitProbeCtxt<'_, '_, Infcx, I, F> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, F: FnOnce(&QueryResult) -> inspect::ProbeKind, { @@ -80,7 +81,7 @@ where impl<'a, Infcx, I> EvalCtxt<'a, Infcx, I> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { /// `probe_kind` is only called when proof tree building is enabled so it can be diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs similarity index 95% rename from compiler/rustc_trait_selection/src/solve/inspect/build.rs rename to compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index 35750598bc74..5fbec4b28d43 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -3,16 +3,19 @@ //! This code is *a bit* of a mess and can hopefully be //! mostly ignored. For a general overview of how it works, //! see the comment on [ProofTreeBuilder]. + use std::marker::PhantomData; use std::mem; +use rustc_type_ir::{self as ty, Interner}; + +use crate::infcx::SolverDelegate; use crate::solve::eval_ctxt::canonical; -use crate::solve::{self, inspect, GenerateProofTree}; -use rustc_middle::bug; -use rustc_next_trait_solver::solve::{ - CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult, +use crate::solve::inspect; +use crate::solve::{ + CanonicalInput, Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource, QueryInput, + QueryResult, }; -use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; /// The core data structure when building proof trees. /// @@ -34,9 +37,9 @@ use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; /// trees. At the end of trait solving `ProofTreeBuilder::finalize` /// is called to recursively convert the whole structure to a /// finished proof tree. -pub(in crate::solve) struct ProofTreeBuilder::Interner> +pub(in crate::solve) struct ProofTreeBuilder::Interner> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { _infcx: PhantomData, @@ -170,7 +173,7 @@ impl WipCanonicalGoalEvaluationStep { for _ in 0..self.probe_depth { match current.steps.last_mut() { Some(WipProbeStep::NestedProbe(p)) => current = p, - _ => bug!(), + _ => panic!(), } } current @@ -232,7 +235,7 @@ impl WipProbeStep { } } -impl, I: Interner> ProofTreeBuilder { +impl, I: Interner> ProofTreeBuilder { fn new(state: impl Into>) -> ProofTreeBuilder { ProofTreeBuilder { state: Some(Box::new(state.into())), _infcx: PhantomData } } @@ -293,15 +296,15 @@ impl, I: Interner> ProofTreeBuilder { &mut self, goal: Goal, orig_values: &[I::GenericArg], - kind: solve::GoalEvaluationKind, + kind: GoalEvaluationKind, ) -> ProofTreeBuilder { self.opt_nested(|| match kind { - solve::GoalEvaluationKind::Root => Some(WipGoalEvaluation { + GoalEvaluationKind::Root => Some(WipGoalEvaluation { uncanonicalized_goal: goal, orig_values: orig_values.to_vec(), evaluation: None, }), - solve::GoalEvaluationKind::Nested => None, + GoalEvaluationKind::Nested => None, }) } @@ -413,7 +416,7 @@ impl, I: Interner> ProofTreeBuilder { Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { state.var_values.push(arg.into()); } - Some(s) => bug!("tried to add var values to {s:?}"), + Some(s) => panic!("tried to add var values to {s:?}"), } } @@ -430,7 +433,7 @@ impl, I: Interner> ProofTreeBuilder { })); state.probe_depth += 1; } - Some(s) => bug!("tried to start probe to {s:?}"), + Some(s) => panic!("tried to start probe to {s:?}"), } } @@ -441,7 +444,7 @@ impl, I: Interner> ProofTreeBuilder { let prev = state.current_evaluation_scope().kind.replace(probe_kind); assert_eq!(prev, None); } - _ => bug!(), + _ => panic!(), } } @@ -458,7 +461,7 @@ impl, I: Interner> ProofTreeBuilder { let prev = state.current_evaluation_scope().final_state.replace(final_state); assert_eq!(prev, None); } - _ => bug!(), + _ => panic!(), } } @@ -494,7 +497,7 @@ impl, I: Interner> ProofTreeBuilder { ); state.current_evaluation_scope().steps.push(WipProbeStep::AddGoal(source, goal)) } - _ => bug!(), + _ => panic!(), } } @@ -518,7 +521,7 @@ impl, I: Interner> ProofTreeBuilder { .push(WipProbeStep::RecordImplArgs { impl_args }); } None => {} - _ => bug!(), + _ => panic!(), } } @@ -531,7 +534,7 @@ impl, I: Interner> ProofTreeBuilder { .push(WipProbeStep::MakeCanonicalResponse { shallow_certainty }); } None => {} - _ => bug!(), + _ => panic!(), } } @@ -544,7 +547,7 @@ impl, I: Interner> ProofTreeBuilder { state.var_values.truncate(num_var_values); state.probe_depth -= 1; } - _ => bug!(), + _ => panic!(), } self diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs new file mode 100644 index 000000000000..0d8c00601269 --- /dev/null +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs @@ -0,0 +1,6 @@ +pub use rustc_type_ir::solve::inspect::*; + +mod build; +pub(in crate::solve) use build::*; + +pub use crate::solve::eval_ctxt::canonical::instantiate_canonical_state; diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs similarity index 72% rename from compiler/rustc_trait_selection/src/solve/mod.rs rename to compiler/rustc_next_trait_solver/src/solve/mod.rs index 4f1be5cbc853..02069016c2bd 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -13,38 +13,23 @@ //! //! FIXME(@lcnr): Write that section. If you read this before then ask me //! about it on zulip. -use rustc_hir::def_id::DefId; -use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; -use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::query::NoSolution; -use rustc_macros::extension; -use rustc_middle::bug; -use rustc_middle::infer::canonical::CanonicalVarInfos; -use rustc_middle::traits::solve::{ - CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, QueryResult, Response, -}; -use rustc_middle::ty::{ - self, AliasRelationDirection, CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, Ty, - TyCtxt, TypeOutlivesPredicate, UniverseIndex, -}; mod alias_relate; mod assembly; mod eval_ctxt; -mod fulfill; pub mod inspect; -mod normalize; mod normalizes_to; mod project_goals; mod search_graph; -mod select; mod trait_goals; -pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt}; -pub use fulfill::{FulfillmentCtxt, NextSolverError}; -pub(crate) use normalize::deeply_normalize_for_diagnostics; -pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; -pub use select::InferCtxtSelectExt; +use rustc_type_ir::inherent::*; +pub use rustc_type_ir::solve::*; +use rustc_type_ir::{self as ty, Interner}; +use tracing::instrument; + +pub use self::eval_ctxt::{EvalCtxt, GenerateProofTree, SolverDelegateEvalExt}; +use crate::infcx::SolverDelegate; /// How many fixpoint iterations we should attempt inside of the solver before bailing /// with overflow. @@ -57,40 +42,30 @@ pub use select::InferCtxtSelectExt; /// recursion limit again. However, this feels very unlikely. const FIXPOINT_STEP_LIMIT: usize = 8; -#[derive(Debug, Clone, Copy)] -enum SolverMode { - /// Ordinary trait solving, using everywhere except for coherence. - Normal, - /// Trait solving during coherence. There are a few notable differences - /// between coherence and ordinary trait solving. - /// - /// Most importantly, trait solving during coherence must not be incomplete, - /// i.e. return `Err(NoSolution)` for goals for which a solution exists. - /// This means that we must not make any guesses or arbitrary choices. - Coherence, -} - #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum GoalEvaluationKind { Root, Nested, } -#[extension(trait CanonicalResponseExt)] -impl<'tcx> Canonical<'tcx, Response>> { - fn has_no_inference_or_external_constraints(&self) -> bool { - self.value.external_constraints.region_constraints.is_empty() - && self.value.var_values.is_identity() - && self.value.external_constraints.opaque_types.is_empty() - } +fn has_no_inference_or_external_constraints( + response: ty::Canonical>, +) -> bool { + response.value.external_constraints.region_constraints.is_empty() + && response.value.var_values.is_identity() + && response.value.external_constraints.opaque_types.is_empty() } -impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { +impl<'a, Infcx, I> EvalCtxt<'a, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ #[instrument(level = "trace", skip(self))] fn compute_type_outlives_goal( &mut self, - goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal>, + ) -> QueryResult { let ty::OutlivesPredicate(ty, lt) = goal.predicate; self.register_ty_outlives(ty, lt); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) @@ -99,21 +74,18 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self))] fn compute_region_outlives_goal( &mut self, - goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal>, + ) -> QueryResult { let ty::OutlivesPredicate(a, b) = goal.predicate; self.register_region_outlives(a, b); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } #[instrument(level = "trace", skip(self))] - fn compute_coerce_goal( - &mut self, - goal: Goal<'tcx, CoercePredicate<'tcx>>, - ) -> QueryResult<'tcx> { + fn compute_coerce_goal(&mut self, goal: Goal>) -> QueryResult { self.compute_subtype_goal(Goal { param_env: goal.param_env, - predicate: SubtypePredicate { + predicate: ty::SubtypePredicate { a_is_expected: false, a: goal.predicate.a, b: goal.predicate.b, @@ -122,10 +94,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } #[instrument(level = "trace", skip(self))] - fn compute_subtype_goal( - &mut self, - goal: Goal<'tcx, SubtypePredicate<'tcx>>, - ) -> QueryResult<'tcx> { + fn compute_subtype_goal(&mut self, goal: Goal>) -> QueryResult { if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() { self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } else { @@ -134,8 +103,8 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } } - fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> { - if self.interner().is_object_safe(trait_def_id) { + fn compute_object_safe_goal(&mut self, trait_def_id: I::DefId) -> QueryResult { + if self.interner().trait_is_object_safe(trait_def_id) { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) @@ -143,10 +112,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } #[instrument(level = "trace", skip(self))] - fn compute_well_formed_goal( - &mut self, - goal: Goal<'tcx, ty::GenericArg<'tcx>>, - ) -> QueryResult<'tcx> { + fn compute_well_formed_goal(&mut self, goal: Goal) -> QueryResult { match self.well_formed_goals(goal.param_env, goal.predicate) { Some(goals) => { self.add_goals(GoalSource::Misc, goals); @@ -159,8 +125,8 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self))] fn compute_const_evaluatable_goal( &mut self, - Goal { param_env, predicate: ct }: Goal<'tcx, ty::Const<'tcx>>, - ) -> QueryResult<'tcx> { + Goal { param_env, predicate: ct }: Goal, + ) -> QueryResult { match ct.kind() { ty::ConstKind::Unevaluated(uv) => { // We never return `NoSolution` here as `try_const_eval_resolve` emits an @@ -190,7 +156,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { // - `Bound` cannot exist as we don't have a binder around the self Type // - `Expr` is part of `feature(generic_const_exprs)` and is not implemented yet ty::ConstKind::Param(_) | ty::ConstKind::Bound(_, _) | ty::ConstKind::Expr(_) => { - bug!("unexpect const kind: {:?}", ct) + panic!("unexpect const kind: {:?}", ct) } } } @@ -198,8 +164,8 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self), ret)] fn compute_const_arg_has_type_goal( &mut self, - goal: Goal<'tcx, (ty::Const<'tcx>, Ty<'tcx>)>, - ) -> QueryResult<'tcx> { + goal: Goal, + ) -> QueryResult { let (ct, ty) = goal.predicate; let ct_ty = match ct.kind() { @@ -216,7 +182,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } ty::ConstKind::Unevaluated(uv) => { - self.interner().type_of(uv.def).instantiate(self.interner(), uv.args) + self.interner().type_of(uv.def).instantiate(self.interner(), &uv.args) } ty::ConstKind::Expr(_) => unimplemented!( "`feature(generic_const_exprs)` is not supported in the new trait solver" @@ -224,10 +190,10 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { ty::ConstKind::Param(_) => { unreachable!("`ConstKind::Param` should have been canonicalized to `Placeholder`") } - ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct), + ty::ConstKind::Bound(_, _) => panic!("escaping bound vars in {:?}", ct), ty::ConstKind::Value(ty, _) => ty, ty::ConstKind::Placeholder(placeholder) => { - placeholder.find_const_ty_from_env(goal.param_env) + self.interner().find_const_ty_from_env(goal.param_env, placeholder) } }; @@ -236,15 +202,19 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } } -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +impl EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ /// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`. /// /// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`. #[instrument(level = "trace", skip(self), ret)] fn try_merge_responses( &mut self, - responses: &[CanonicalResponse<'tcx>], - ) -> Option> { + responses: &[CanonicalResponse], + ) -> Option> { if responses.is_empty() { return None; } @@ -260,14 +230,14 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { .iter() .find(|response| { response.value.certainty == Certainty::Yes - && response.has_no_inference_or_external_constraints() + && has_no_inference_or_external_constraints(**response) }) .copied() } /// If we fail to merge responses we flounder and return overflow or ambiguity. #[instrument(level = "trace", skip(self), ret)] - fn flounder(&mut self, responses: &[CanonicalResponse<'tcx>]) -> QueryResult<'tcx> { + fn flounder(&mut self, responses: &[CanonicalResponse]) -> QueryResult { if responses.is_empty() { return Err(NoSolution); } @@ -277,7 +247,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { certainty.unify_with(response.value.certainty) }) else { - bug!("expected flounder response to be ambiguous") + panic!("expected flounder response to be ambiguous") }; Ok(self.make_ambiguous_response_no_constraints(maybe_cause)) @@ -291,9 +261,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self, param_env), ret)] fn structurally_normalize_ty( &mut self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - ) -> Result, NoSolution> { + param_env: I::ParamEnv, + ty: I::Ty, + ) -> Result { if let ty::Alias(..) = ty.kind() { let normalized_ty = self.next_ty_infer(); let alias_relate_goal = Goal::new( @@ -302,7 +272,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ty::PredicateKind::AliasRelate( ty.into(), normalized_ty.into(), - AliasRelationDirection::Equate, + ty::AliasRelationDirection::Equate, ), ); self.add_goal(GoalSource::Misc, alias_relate_goal); @@ -314,17 +284,17 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } } -fn response_no_constraints_raw<'tcx>( - tcx: TyCtxt<'tcx>, - max_universe: UniverseIndex, - variables: CanonicalVarInfos<'tcx>, +fn response_no_constraints_raw( + tcx: I, + max_universe: ty::UniverseIndex, + variables: I::CanonicalVars, certainty: Certainty, -) -> CanonicalResponse<'tcx> { - Canonical { +) -> CanonicalResponse { + ty::Canonical { max_universe, variables, value: Response { - var_values: CanonicalVarValues::make_identity(tcx, variables), + var_values: ty::CanonicalVarValues::make_identity(tcx, variables), // FIXME: maybe we should store the "no response" version in tcx, like // we do for tcx.types and stuff. external_constraints: tcx.mk_external_constraints(ExternalConstraintsData::default()), diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs similarity index 64% rename from compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs rename to compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs index a6e4b6ff4a81..0f1c1f13c165 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs @@ -1,14 +1,19 @@ -use crate::solve::EvalCtxt; -use rustc_infer::infer::InferCtxt; -use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; -use rustc_middle::ty; +use rustc_type_ir::{self as ty, Interner}; +use tracing::instrument; -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +use crate::infcx::SolverDelegate; +use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult}; + +impl EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ #[instrument(level = "trace", skip(self), ret)] pub(super) fn normalize_anon_const( &mut self, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal>, + ) -> QueryResult { if let Some(normalized_const) = self.try_const_eval_resolve( goal.param_env, ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args), diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs similarity index 75% rename from compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs rename to compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 41b2b9cd4d26..8436f3ad4841 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -4,17 +4,21 @@ //! 1. instantiate generic parameters, //! 2. equate the self type, and //! 3. instantiate and register where clauses. -use rustc_infer::infer::InferCtxt; -use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult}; -use rustc_middle::ty; -use crate::solve::EvalCtxt; +use rustc_type_ir::{self as ty, Interner}; -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +use crate::infcx::SolverDelegate; +use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult}; + +impl EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ pub(super) fn normalize_inherent_associated_type( &mut self, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal>, + ) -> QueryResult { let tcx = self.interner(); let inherent = goal.predicate.alias.expect_ty(tcx); @@ -25,7 +29,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.eq( goal.param_env, inherent.self_ty(), - tcx.type_of(impl_def_id).instantiate(tcx, impl_args), + tcx.type_of(impl_def_id).instantiate(tcx, &impl_args), )?; // Equate IAT with the RHS of the project goal @@ -40,12 +44,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.add_goals( GoalSource::Misc, tcx.predicates_of(inherent.def_id) - .instantiate(tcx, inherent_args) - .into_iter() - .map(|(pred, _)| goal.with(tcx, pred)), + .iter_instantiated(tcx, &inherent_args) + .map(|pred| goal.with(tcx, pred)), ); - let normalized = tcx.type_of(inherent.def_id).instantiate(tcx, inherent_args); + let normalized = tcx.type_of(inherent.def_id).instantiate(tcx, &inherent_args); self.instantiate_normalizes_to_term(goal, normalized.into()); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs similarity index 63% rename from compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs rename to compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 5c5923e9d396..ebc83bef5137 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -1,35 +1,33 @@ -use crate::traits::specialization_graph::{self, LeafDef, Node}; - -use super::assembly::structural_traits::AsyncCallableRelevantTypes; -use super::assembly::{self, structural_traits, Candidate}; -use super::{EvalCtxt, GoalSource}; -use rustc_hir::def_id::DefId; -use rustc_hir::LangItem; -use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::query::NoSolution; -use rustc_infer::traits::solve::inspect::ProbeKind; -use rustc_infer::traits::solve::MaybeCause; -use rustc_infer::traits::Reveal; -use rustc_middle::bug; -use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult}; -use rustc_middle::traits::BuiltinImplSource; -use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::NormalizesTo; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::ty::{TypeVisitableExt, Upcast}; -use rustc_span::{ErrorGuaranteed, DUMMY_SP}; - mod anon_const; mod inherent; mod opaque_types; mod weak_types; -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +use rustc_type_ir::inherent::*; +use rustc_type_ir::lang_items::TraitSolverLangItem; +use rustc_type_ir::Upcast as _; +use rustc_type_ir::{self as ty, Interner, NormalizesTo}; +use tracing::instrument; + +use crate::infcx::SolverDelegate; +use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes}; +use crate::solve::assembly::{self, Candidate}; +use crate::solve::inspect::ProbeKind; +use crate::solve::{ + BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause, + NoSolution, QueryResult, +}; + +impl EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ #[instrument(level = "trace", skip(self), ret)] pub(super) fn compute_normalizes_to_goal( &mut self, - goal: Goal<'tcx, NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal>, + ) -> QueryResult { self.set_is_normalizes_to_goal(); debug_assert!(self.term_is_fully_unconstrained(goal)); let normalize_result = self @@ -49,10 +47,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// Normalize the given alias by at least one step. If the alias is rigid, this /// returns `NoSolution`. #[instrument(level = "trace", skip(self), ret)] - fn normalize_at_least_one_step( - &mut self, - goal: Goal<'tcx, NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { + fn normalize_at_least_one_step(&mut self, goal: Goal>) -> QueryResult { match goal.predicate.alias.kind(self.interner()) { ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { let candidates = self.assemble_and_evaluate_candidates(goal); @@ -72,38 +67,42 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// emit nested `AliasRelate` goals to structurally normalize the alias. pub fn instantiate_normalizes_to_term( &mut self, - goal: Goal<'tcx, NormalizesTo<'tcx>>, - term: ty::Term<'tcx>, + goal: Goal>, + term: I::Term, ) { self.eq(goal.param_env, goal.predicate.term, term) .expect("expected goal term to be fully unconstrained"); } } -impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { - fn self_ty(self) -> Ty<'tcx> { +impl assembly::GoalKind for NormalizesTo +where + Infcx: SolverDelegate, + I: Interner, +{ + fn self_ty(self) -> I::Ty { self.self_ty() } - fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { + fn trait_ref(self, tcx: I) -> ty::TraitRef { self.alias.trait_ref(tcx) } - fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { + fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self { self.with_self_ty(tcx, self_ty) } - fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { + fn trait_def_id(self, tcx: I) -> I::DefId { self.trait_def_id(tcx) } fn probe_and_match_goal_against_assumption( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - source: CandidateSource<'tcx>, - goal: Goal<'tcx, Self>, - assumption: ty::Clause<'tcx>, - then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + source: CandidateSource, + goal: Goal, + assumption: I::Clause, + then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult, + ) -> Result, NoSolution> { if let Some(projection_pred) = assumption.as_projection_clause() { if projection_pred.projection_def_id() == goal.predicate.def_id() { let tcx = ecx.interner(); @@ -121,9 +120,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { // Add GAT where clauses from the trait's definition ecx.add_goals( GoalSource::Misc, - tcx.predicates_of(goal.predicate.def_id()) - .instantiate_own(tcx, goal.predicate.alias.args) - .map(|(pred, _)| goal.with(tcx, pred)), + tcx.own_predicates_of(goal.predicate.def_id()) + .iter_instantiated(tcx, &goal.predicate.alias.args) + .map(|pred| goal.with(tcx, pred)), ); then(ecx) @@ -137,24 +136,23 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_impl_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, NormalizesTo<'tcx>>, - impl_def_id: DefId, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal>, + impl_def_id: I::DefId, + ) -> Result, NoSolution> { let tcx = ecx.interner(); let goal_trait_ref = goal.predicate.alias.trait_ref(tcx); - let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); - let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; - if !drcx.args_may_unify( - goal.predicate.trait_ref(tcx).args, - impl_trait_header.trait_ref.skip_binder().args, + let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); + if !ecx.interner().args_may_unify_deep( + goal.predicate.alias.trait_ref(tcx).args, + impl_trait_ref.skip_binder().args, ) { return Err(NoSolution); } // We have to ignore negative impls when projecting. - let impl_polarity = impl_trait_header.polarity; + let impl_polarity = tcx.impl_polarity(impl_def_id); match impl_polarity { ty::ImplPolarity::Negative => return Err(NoSolution), ty::ImplPolarity::Reservation => { @@ -165,30 +163,28 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| { let impl_args = ecx.fresh_args_for_item(impl_def_id); - let impl_trait_ref = impl_trait_header.trait_ref.instantiate(tcx, impl_args); + let impl_trait_ref = impl_trait_ref.instantiate(tcx, &impl_args); ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?; let where_clause_bounds = tcx .predicates_of(impl_def_id) - .instantiate(tcx, impl_args) - .predicates - .into_iter() + .iter_instantiated(tcx, &impl_args) .map(|pred| goal.with(tcx, pred)); ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); // Add GAT where clauses from the trait's definition ecx.add_goals( GoalSource::Misc, - tcx.predicates_of(goal.predicate.def_id()) - .instantiate_own(tcx, goal.predicate.alias.args) - .map(|(pred, _)| goal.with(tcx, pred)), + tcx.own_predicates_of(goal.predicate.def_id()) + .iter_instantiated(tcx, &goal.predicate.alias.args) + .map(|pred| goal.with(tcx, pred)), ); // In case the associated item is hidden due to specialization, we have to // return ambiguity this would otherwise be incomplete, resulting in // unsoundness during coherence (#105782). - let Some(assoc_def) = ecx.fetch_eligible_assoc_item_def( + let Some(target_item_def_id) = ecx.fetch_eligible_assoc_item( goal.param_env, goal_trait_ref, goal.predicate.def_id(), @@ -198,21 +194,23 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); }; - let error_response = |ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, reason| { - let guar = tcx.dcx().span_delayed_bug(tcx.def_span(assoc_def.item.def_id), reason); + let error_response = |ecx: &mut EvalCtxt<'_, Infcx>, msg: &str| { + let guar = tcx.delay_bug(msg); let error_term = match goal.predicate.alias.kind(tcx) { ty::AliasTermKind::ProjectionTy => Ty::new_error(tcx, guar).into(), - ty::AliasTermKind::ProjectionConst => ty::Const::new_error(tcx, guar).into(), - kind => bug!("expected projection, found {kind:?}"), + ty::AliasTermKind::ProjectionConst => Const::new_error(tcx, guar).into(), + kind => panic!("expected projection, found {kind:?}"), }; ecx.instantiate_normalizes_to_term(goal, error_term); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }; - if !assoc_def.item.defaultness(tcx).has_value() { - return error_response(ecx, "missing value for assoc item in impl"); + if !tcx.has_item_definition(target_item_def_id) { + return error_response(ecx, "missing item"); } + let target_container_def_id = tcx.parent(target_item_def_id); + // Getting the right args here is complex, e.g. given: // - a goal ` as Trait>::Assoc` // - the applicable impl `impl Trait for Vec` @@ -223,39 +221,40 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { // // And then map these args to the args of the defining impl of `Assoc`, going // from `[u32, u64]` to `[u32, i32, u64]`. - let associated_item_args = - ecx.translate_args(&assoc_def, goal, impl_def_id, impl_args, impl_trait_ref)?; + let target_args = ecx.translate_args( + goal, + impl_def_id, + impl_args, + impl_trait_ref, + target_container_def_id, + )?; - if !tcx.check_args_compatible(assoc_def.item.def_id, associated_item_args) { - return error_response( - ecx, - "associated item has mismatched generic item arguments", - ); + if !tcx.check_args_compatible(target_item_def_id, target_args) { + return error_response(ecx, "associated item has mismatched arguments"); } // Finally we construct the actual value of the associated type. let term = match goal.predicate.alias.kind(tcx) { ty::AliasTermKind::ProjectionTy => { - tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()) + tcx.type_of(target_item_def_id).map_bound(|ty| ty.into()) } ty::AliasTermKind::ProjectionConst => { - if tcx.features().associated_const_equality { - bug!("associated const projection is not supported yet") + if tcx.features().associated_const_equality() { + panic!("associated const projection is not supported yet") } else { ty::EarlyBinder::bind( - ty::Const::new_error_with_message( + Const::new_error_with_message( tcx, - DUMMY_SP, "associated const projection is not supported yet", ) .into(), ) } } - kind => bug!("expected projection, found {kind:?}"), + kind => panic!("expected projection, found {kind:?}"), }; - ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, associated_item_args)); + ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, &target_args)); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -263,63 +262,60 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { /// Fail to normalize if the predicate contains an error, alternatively, we could normalize to `ty::Error` /// and succeed. Can experiment with this to figure out what results in better error messages. fn consider_error_guaranteed_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - _guar: ErrorGuaranteed, - ) -> Result>, NoSolution> { + _ecx: &mut EvalCtxt<'_, Infcx>, + _guar: I::ErrorGuaranteed, + ) -> Result, NoSolution> { Err(NoSolution) } fn consider_auto_trait_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { - ecx.interner().dcx().span_delayed_bug( - ecx.interner().def_span(goal.predicate.def_id()), - "associated types not allowed on auto traits", - ); + ecx: &mut EvalCtxt<'_, Infcx>, + _goal: Goal, + ) -> Result, NoSolution> { + ecx.interner().delay_bug("associated types not allowed on auto traits"); Err(NoSolution) } fn consider_trait_alias_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { - bug!("trait aliases do not have associated types: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { + panic!("trait aliases do not have associated types: {:?}", goal); } fn consider_builtin_sized_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { - bug!("`Sized` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { + panic!("`Sized` does not have an associated type: {:?}", goal); } fn consider_builtin_copy_clone_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { - bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { + panic!("`Copy`/`Clone` does not have an associated type: {:?}", goal); } fn consider_builtin_pointer_like_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { - bug!("`PointerLike` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { + panic!("`PointerLike` does not have an associated type: {:?}", goal); } fn consider_builtin_fn_ptr_trait_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { - bug!("`FnPtr` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { + panic!("`FnPtr` does not have an associated type: {:?}", goal); } fn consider_builtin_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, goal_kind: ty::ClosureKind, - ) -> Result>, NoSolution> { + ) -> Result, NoSolution> { let tcx = ecx.interner(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( @@ -333,7 +329,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } }; let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { - ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output]) + ty::TraitRef::new(tcx, tcx.require_lang_item(TraitSolverLangItem::Sized), [output]) }); let pred = tupled_inputs_and_output @@ -359,16 +355,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_async_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, goal_kind: ty::ClosureKind, - ) -> Result>, NoSolution> { + ) -> Result, NoSolution> { let tcx = ecx.interner(); let env_region = match goal_kind { ty::ClosureKind::Fn | ty::ClosureKind::FnMut => goal.predicate.alias.args.region_at(2), // Doesn't matter what this region is - ty::ClosureKind::FnOnce => tcx.lifetimes.re_static, + ty::ClosureKind::FnOnce => Region::new_static(tcx), }; let (tupled_inputs_and_output_and_coroutine, nested_preds) = structural_traits::extract_tupled_inputs_and_output_from_async_callable( @@ -379,7 +375,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { )?; let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( |AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| { - ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output_ty]) + ty::TraitRef::new( + tcx, + tcx.require_lang_item(TraitSolverLangItem::Sized), + [output_ty], + ) }, ); @@ -391,7 +391,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { coroutine_return_ty, }| { let (projection_term, term) = if tcx - .is_lang_item(goal.predicate.def_id(), LangItem::CallOnceFuture) + .is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CallOnceFuture) { ( ty::AliasTerm::new( @@ -401,34 +401,41 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ), output_coroutine_ty.into(), ) - } else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CallRefFuture) { - ( - ty::AliasTerm::new( - tcx, - goal.predicate.def_id(), - [ - ty::GenericArg::from(goal.predicate.self_ty()), - tupled_inputs_ty.into(), - env_region.into(), - ], - ), - output_coroutine_ty.into(), - ) - } else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::AsyncFnOnceOutput) + } else if tcx + .is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CallRefFuture) { ( ty::AliasTerm::new( tcx, goal.predicate.def_id(), [ - ty::GenericArg::from(goal.predicate.self_ty()), + I::GenericArg::from(goal.predicate.self_ty()), + tupled_inputs_ty.into(), + env_region.into(), + ], + ), + output_coroutine_ty.into(), + ) + } else if tcx.is_lang_item( + goal.predicate.def_id(), + TraitSolverLangItem::AsyncFnOnceOutput, + ) { + ( + ty::AliasTerm::new( + tcx, + goal.predicate.def_id(), + [ + I::GenericArg::from(goal.predicate.self_ty()), tupled_inputs_ty.into(), ], ), coroutine_return_ty.into(), ) } else { - bug!("no such associated type in `AsyncFn*`: {:?}", goal.predicate.def_id()) + panic!( + "no such associated type in `AsyncFn*`: {:?}", + goal.predicate.def_id() + ) }; ty::ProjectionPredicate { projection_term, term } }, @@ -450,9 +457,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_async_fn_kind_helper_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { let [ closure_fn_kind_ty, goal_kind_ty, @@ -462,7 +469,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { coroutine_captures_by_ref_ty, ] = **goal.predicate.alias.args else { - bug!(); + panic!(); }; // Bail if the upvars haven't been constrained. @@ -497,18 +504,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_tuple_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { - bug!("`Tuple` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { + panic!("`Tuple` does not have an associated type: {:?}", goal); } fn consider_builtin_pointee_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { let tcx = ecx.interner(); - let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); + let metadata_def_id = tcx.require_lang_item(TraitSolverLangItem::Metadata); assert_eq!(metadata_def_id, goal.predicate.def_id()); ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { let metadata_ty = match goal.predicate.self_ty().kind() { @@ -530,16 +537,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { | ty::CoroutineWitness(..) | ty::Never | ty::Foreign(..) - | ty::Dynamic(_, _, ty::DynStar) => tcx.types.unit, + | ty::Dynamic(_, _, ty::DynStar) => Ty::new_unit(tcx), - ty::Error(e) => Ty::new_error(tcx, *e), + ty::Error(e) => Ty::new_error(tcx, e), - ty::Str | ty::Slice(_) => tcx.types.usize, + ty::Str | ty::Slice(_) => Ty::new_usize(tcx), ty::Dynamic(_, _, ty::Dyn) => { - let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); + let dyn_metadata = tcx.require_lang_item(TraitSolverLangItem::DynMetadata); tcx.type_of(dyn_metadata) - .instantiate(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())]) + .instantiate(tcx, &[I::GenericArg::from(goal.predicate.self_ty())]) } ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { @@ -549,32 +556,31 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { // exist. Instead, `Pointee` should be a supertrait of `Sized`. let sized_predicate = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Sized, None), - [ty::GenericArg::from(goal.predicate.self_ty())], + tcx.require_lang_item(TraitSolverLangItem::Sized), + [I::GenericArg::from(goal.predicate.self_ty())], ); // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`? ecx.add_goal(GoalSource::Misc, goal.with(tcx, sized_predicate)); - tcx.types.unit + Ty::new_unit(tcx) } - ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() { - None => tcx.types.unit, - Some(tail_def) => { - let tail_ty = tail_def.ty(tcx, args); - Ty::new_projection(tcx, metadata_def_id, [tail_ty]) + ty::Adt(def, args) if def.is_struct() => match def.struct_tail_ty(tcx) { + None => Ty::new_unit(tcx), + Some(tail_ty) => { + Ty::new_projection(tcx, metadata_def_id, [tail_ty.instantiate(tcx, &args)]) } }, - ty::Adt(_, _) => tcx.types.unit, + ty::Adt(_, _) => Ty::new_unit(tcx), ty::Tuple(elements) => match elements.last() { - None => tcx.types.unit, + None => Ty::new_unit(tcx), Some(&tail_ty) => Ty::new_projection(tcx, metadata_def_id, [tail_ty]), }, ty::Infer( ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_), ) - | ty::Bound(..) => bug!( + | ty::Bound(..) => panic!( "unexpected self ty `{:?}` when normalizing `::Metadata`", goal.predicate.self_ty() ), @@ -586,11 +592,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_future_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); - let ty::Coroutine(def_id, args) = *self_ty.kind() else { + let ty::Coroutine(def_id, args) = self_ty.kind() else { return Err(NoSolution); }; @@ -622,11 +628,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_iterator_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); - let ty::Coroutine(def_id, args) = *self_ty.kind() else { + let ty::Coroutine(def_id, args) = self_ty.kind() else { return Err(NoSolution); }; @@ -658,18 +664,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_fused_iterator_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { - bug!("`FusedIterator` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { + panic!("`FusedIterator` does not have an associated type: {:?}", goal); } fn consider_builtin_async_iterator_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); - let ty::Coroutine(def_id, args) = *self_ty.kind() else { + let ty::Coroutine(def_id, args) = self_ty.kind() else { return Err(NoSolution); }; @@ -685,10 +691,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { // coroutine yield ty `Poll>`. let wrapped_expected_ty = Ty::new_adt( tcx, - tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)), + tcx.adt_def(tcx.require_lang_item(TraitSolverLangItem::Poll)), tcx.mk_args(&[Ty::new_adt( tcx, - tcx.adt_def(tcx.require_lang_item(LangItem::Option, None)), + tcx.adt_def(tcx.require_lang_item(TraitSolverLangItem::Option)), tcx.mk_args(&[expected_ty.into()]), ) .into()]), @@ -701,11 +707,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_coroutine_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); - let ty::Coroutine(def_id, args) = *self_ty.kind() else { + let ty::Coroutine(def_id, args) = self_ty.kind() else { return Err(NoSolution); }; @@ -717,15 +723,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { let coroutine = args.as_coroutine(); - let term = if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CoroutineReturn) { + let term = if tcx + .is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CoroutineReturn) + { coroutine.return_ty().into() - } else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CoroutineYield) { + } else if tcx.is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CoroutineYield) { coroutine.yield_ty().into() } else { - bug!( - "unexpected associated item `<{self_ty} as Coroutine>::{}`", - tcx.item_name(goal.predicate.def_id()) - ) + panic!("unexpected associated item `{:?}` for `{self_ty:?}`", goal.predicate.def_id()) }; Self::probe_and_consider_implied_clause( @@ -748,18 +753,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_structural_builtin_unsize_candidates( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Vec>> { - bug!("`Unsize` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Vec> { + panic!("`Unsize` does not have an associated type: {:?}", goal); } fn consider_builtin_discriminant_kind_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); - let discriminant_ty = match *self_ty.kind() { + let discriminant_ty = match self_ty.kind() { ty::Bool | ty::Char | ty::Int(..) @@ -794,7 +799,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) - | ty::Bound(..) => bug!( + | ty::Bound(..) => panic!( "unexpected self ty `{:?}` when normalizing `::Discriminant`", goal.predicate.self_ty() ), @@ -807,11 +812,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_async_destruct_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); - let async_destructor_ty = match *self_ty.kind() { + let async_destructor_ty = match self_ty.kind() { ty::Bool | ty::Char | ty::Int(..) @@ -842,12 +847,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Foreign(..) - | ty::Bound(..) => bug!( + | ty::Bound(..) => panic!( "unexpected self ty `{:?}` when normalizing `::AsyncDestructor`", goal.predicate.self_ty() ), - ty::Pat(..) | ty::Dynamic(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) => bug!( + ty::Pat(..) | ty::Dynamic(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) => panic!( "`consider_builtin_async_destruct_candidate` is not yet implemented for type: {self_ty:?}" ), }; @@ -860,93 +865,56 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_destruct_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { - bug!("`Destruct` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { + panic!("`Destruct` does not have an associated type: {:?}", goal); } fn consider_builtin_transmute_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { - bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { + panic!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) } } -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +impl EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ fn translate_args( &mut self, - assoc_def: &LeafDef, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, - impl_def_id: DefId, - impl_args: ty::GenericArgsRef<'tcx>, - impl_trait_ref: rustc_type_ir::TraitRef>, - ) -> Result, NoSolution> { + goal: Goal>, + impl_def_id: I::DefId, + impl_args: I::GenericArgs, + impl_trait_ref: rustc_type_ir::TraitRef, + target_container_def_id: I::DefId, + ) -> Result { let tcx = self.interner(); - Ok(match assoc_def.defining_node { - Node::Trait(_) => goal.predicate.alias.args, - Node::Impl(target_impl_def_id) => { - if target_impl_def_id == impl_def_id { - // Same impl, no need to fully translate, just a rebase from - // the trait is sufficient. - goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, impl_args) - } else { - let target_args = self.fresh_args_for_item(target_impl_def_id); - let target_trait_ref = tcx - .impl_trait_ref(target_impl_def_id) - .unwrap() - .instantiate(tcx, target_args); - // Relate source impl to target impl by equating trait refs. - self.eq(goal.param_env, impl_trait_ref, target_trait_ref)?; - // Also add predicates since they may be needed to constrain the - // target impl's params. - self.add_goals( - GoalSource::Misc, - tcx.predicates_of(target_impl_def_id) - .instantiate(tcx, target_args) - .into_iter() - .map(|(pred, _)| goal.with(tcx, pred)), - ); - goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, target_args) - } - } + Ok(if target_container_def_id == impl_trait_ref.def_id { + // Default value from the trait definition. No need to rebase. + goal.predicate.alias.args + } else if target_container_def_id == impl_def_id { + // Same impl, no need to fully translate, just a rebase from + // the trait is sufficient. + goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, impl_args) + } else { + let target_args = self.fresh_args_for_item(target_container_def_id); + let target_trait_ref = + tcx.impl_trait_ref(target_container_def_id).instantiate(tcx, &target_args); + // Relate source impl to target impl by equating trait refs. + self.eq(goal.param_env, impl_trait_ref, target_trait_ref)?; + // Also add predicates since they may be needed to constrain the + // target impl's params. + self.add_goals( + GoalSource::Misc, + tcx.predicates_of(target_container_def_id) + .iter_instantiated(tcx, &target_args) + .map(|pred| goal.with(tcx, pred)), + ); + goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, target_args) }) } - - /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code. - /// - /// FIXME: We should merge these 3 implementations as it's likely that they otherwise - /// diverge. - #[instrument(level = "trace", skip(self, param_env), ret)] - fn fetch_eligible_assoc_item_def( - &self, - param_env: ty::ParamEnv<'tcx>, - goal_trait_ref: ty::TraitRef<'tcx>, - trait_assoc_def_id: DefId, - impl_def_id: DefId, - ) -> Result, NoSolution> { - let node_item = - specialization_graph::assoc_def(self.interner(), impl_def_id, trait_assoc_def_id) - .map_err(|ErrorGuaranteed { .. }| NoSolution)?; - - let eligible = if node_item.is_final() { - // Non-specializable items are always projectable. - true - } else { - // Only reveal a specializable default if we're past type-checking - // and the obligation is monomorphic, otherwise passes such as - // transmute checking and polymorphic MIR optimizations could - // get a result which isn't correct for all monomorphizations. - if param_env.reveal() == Reveal::All { - let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref); - !poly_trait_ref.still_further_specializable() - } else { - trace!(?node_item.item.def_id, "not eligible due to default"); - false - } - }; - - if eligible { Ok(Some(node_item)) } else { Ok(None) } - } } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs similarity index 64% rename from compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs rename to compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index 82464470b2a2..710671b45d0e 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -1,20 +1,23 @@ //! Computes a normalizes-to (projection) goal for opaque types. This goal //! behaves differently depending on the param-env's reveal mode and whether //! the opaque is in a defining scope. -use rustc_infer::infer::InferCtxt; -use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; -use rustc_middle::traits::Reveal; -use rustc_middle::ty; -use rustc_middle::ty::util::NotUniqueParam; -use crate::solve::{EvalCtxt, SolverMode}; +use rustc_index::bit_set::GrowableBitSet; +use rustc_type_ir::inherent::*; +use rustc_type_ir::{self as ty, Interner}; -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +use crate::infcx::SolverDelegate; +use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, Reveal, SolverMode}; + +impl EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ pub(super) fn normalize_opaque_type( &mut self, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal>, + ) -> QueryResult { let tcx = self.interner(); let opaque_ty = goal.predicate.alias; let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const"); @@ -31,7 +34,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { return Err(NoSolution); } // FIXME: This may have issues when the args contain aliases... - match self.interner().uses_unique_placeholders_ignoring_regions(opaque_ty.args) { + match uses_unique_placeholders_ignoring_regions(self.interner(), opaque_ty.args) { Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => { return self.evaluate_added_goals_and_make_canonical_response( Certainty::AMBIGUOUS, @@ -60,6 +63,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } // Otherwise, define a new opaque type + // FIXME: should we use `inject_hidden_type_unchecked` here? self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?; self.add_item_bounds_for_hidden_type( opaque_ty.def_id, @@ -82,10 +86,51 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } (Reveal::All, _) => { // FIXME: Add an assertion that opaque type storage is empty. - let actual = tcx.type_of(opaque_ty.def_id).instantiate(tcx, opaque_ty.args); + let actual = tcx.type_of(opaque_ty.def_id).instantiate(tcx, &opaque_ty.args); self.eq(goal.param_env, expected, actual)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } } } + +/// Checks whether each generic argument is simply a unique generic placeholder. +/// +/// FIXME: Interner argument is needed to constrain the `I` parameter. +pub fn uses_unique_placeholders_ignoring_regions( + _interner: I, + args: I::GenericArgs, +) -> Result<(), NotUniqueParam> { + let mut seen = GrowableBitSet::default(); + for arg in args { + match arg.kind() { + // Ignore regions, since we can't resolve those in a canonicalized + // query in the trait solver. + ty::GenericArgKind::Lifetime(_) => {} + ty::GenericArgKind::Type(t) => match t.kind() { + ty::Placeholder(p) => { + if !seen.insert(p.var()) { + return Err(NotUniqueParam::DuplicateParam(t.into())); + } + } + _ => return Err(NotUniqueParam::NotParam(t.into())), + }, + ty::GenericArgKind::Const(c) => match c.kind() { + ty::ConstKind::Placeholder(p) => { + if !seen.insert(p.var()) { + return Err(NotUniqueParam::DuplicateParam(c.into())); + } + } + _ => return Err(NotUniqueParam::NotParam(c.into())), + }, + } + } + + Ok(()) +} + +// FIXME: This should check for dupes and non-params first, then infer vars. +pub enum NotUniqueParam { + DuplicateParam(I::GenericArg), + NotParam(I::GenericArg), +} diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs similarity index 67% rename from compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs rename to compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs index 5442b9ccffc8..45341917bb24 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs @@ -3,17 +3,21 @@ //! //! Since a weak alias is never ambiguous, this just computes the `type_of` of //! the alias and registers the where-clauses of the type alias. -use rustc_infer::infer::InferCtxt; -use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult}; -use rustc_middle::ty; -use crate::solve::EvalCtxt; +use rustc_type_ir::{self as ty, Interner}; -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +use crate::infcx::SolverDelegate; +use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult}; + +impl EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ pub(super) fn normalize_weak_type( &mut self, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal>, + ) -> QueryResult { let tcx = self.interner(); let weak_ty = goal.predicate.alias; @@ -21,13 +25,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.add_goals( GoalSource::Misc, tcx.predicates_of(weak_ty.def_id) - .instantiate(tcx, weak_ty.args) - .predicates - .into_iter() + .iter_instantiated(tcx, &weak_ty.args) .map(|pred| goal.with(tcx, pred)), ); - let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, weak_ty.args); + let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, &weak_ty.args); self.instantiate_normalizes_to_term(goal, actual.into()); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs similarity index 61% rename from compiler/rustc_trait_selection/src/solve/project_goals.rs rename to compiler/rustc_next_trait_solver/src/solve/project_goals.rs index cae73cc2d073..4bb1fe5be6f0 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs @@ -1,16 +1,19 @@ -use crate::solve::GoalSource; +use rustc_type_ir::{self as ty, Interner, ProjectionPredicate}; +use tracing::instrument; -use super::EvalCtxt; -use rustc_infer::infer::InferCtxt; -use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; -use rustc_middle::ty::{self, ProjectionPredicate}; +use crate::infcx::SolverDelegate; +use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult}; -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +impl EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ #[instrument(level = "trace", skip(self), ret)] pub(super) fn compute_projection_goal( &mut self, - goal: Goal<'tcx, ProjectionPredicate<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal>, + ) -> QueryResult { let tcx = self.interner(); let projection_term = goal.predicate.projection_term.to_term(tcx); let goal = goal.with( diff --git a/compiler/rustc_trait_selection/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs similarity index 88% rename from compiler/rustc_trait_selection/src/solve/search_graph.rs rename to compiler/rustc_next_trait_solver/src/solve/search_graph.rs index 84878fea1013..b923a121d814 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -1,22 +1,19 @@ use std::mem; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_index::Idx; -use rustc_index::IndexVec; -use rustc_infer::infer::InferCtxt; -use rustc_middle::dep_graph::dep_kinds; -use rustc_middle::traits::solve::CacheData; -use rustc_middle::traits::solve::EvaluationCache; -use rustc_middle::ty::TyCtxt; -use rustc_next_trait_solver::solve::{CanonicalInput, Certainty, QueryResult}; -use rustc_session::Limit; +use rustc_index::{Idx, IndexVec}; use rustc_type_ir::inherent::*; use rustc_type_ir::Interner; +use tracing::debug; -use super::inspect; -use super::inspect::ProofTreeBuilder; -use super::SolverMode; -use crate::solve::FIXPOINT_STEP_LIMIT; +use crate::infcx::SolverDelegate; +use crate::solve::inspect::{self, ProofTreeBuilder}; +use crate::solve::{ + CacheData, CanonicalInput, Certainty, QueryResult, SolverMode, FIXPOINT_STEP_LIMIT, +}; + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct SolverLimit(usize); rustc_index::newtype_index! { #[orderable] @@ -39,7 +36,7 @@ bitflags::bitflags! { struct StackEntry { input: CanonicalInput, - available_depth: Limit, + available_depth: SolverLimit, /// The maximum depth reached by this stack entry, only up-to date /// for the top of the stack and lazily updated for the rest. @@ -168,19 +165,19 @@ impl SearchGraph { fn allowed_depth_for_nested( tcx: I, stack: &IndexVec>, - ) -> Option { + ) -> Option { if let Some(last) = stack.raw.last() { if last.available_depth.0 == 0 { return None; } Some(if last.encountered_overflow { - Limit(last.available_depth.0 / 4) + SolverLimit(last.available_depth.0 / 4) } else { - Limit(last.available_depth.0 - 1) + SolverLimit(last.available_depth.0 - 1) }) } else { - Some(Limit(tcx.recursion_limit())) + Some(SolverLimit(tcx.recursion_limit())) } } @@ -240,34 +237,26 @@ impl SearchGraph { !entry.is_empty() }); } -} -impl<'tcx> SearchGraph> { /// The trait solver behavior is different for coherence /// so we use a separate cache. Alternatively we could use /// a single cache and share it between coherence and ordinary /// trait solving. - pub(super) fn global_cache(&self, tcx: TyCtxt<'tcx>) -> &'tcx EvaluationCache<'tcx> { - match self.mode { - SolverMode::Normal => &tcx.new_solver_evaluation_cache, - SolverMode::Coherence => &tcx.new_solver_coherence_evaluation_cache, - } + pub(super) fn global_cache(&self, tcx: I) -> I::EvaluationCache { + tcx.evaluation_cache(self.mode) } /// Probably the most involved method of the whole solver. /// /// Given some goal which is proven via the `prove_goal` closure, this /// handles caching, overflow, and coinductive cycles. - pub(super) fn with_new_goal( + pub(super) fn with_new_goal>( &mut self, - tcx: TyCtxt<'tcx>, - input: CanonicalInput>, - inspect: &mut ProofTreeBuilder>, - mut prove_goal: impl FnMut( - &mut Self, - &mut ProofTreeBuilder>, - ) -> QueryResult>, - ) -> QueryResult> { + tcx: I, + input: CanonicalInput, + inspect: &mut ProofTreeBuilder, + mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder) -> QueryResult, + ) -> QueryResult { self.check_invariants(); // Check for overflow. let Some(available_depth) = Self::allowed_depth_for_nested(tcx, &self.stack) else { @@ -361,21 +350,20 @@ impl<'tcx> SearchGraph> { // not tracked by the cache key and from outside of this anon task, it // must not be added to the global cache. Notably, this is the case for // trait solver cycles participants. - let ((final_entry, result), dep_node) = - tcx.dep_graph.with_anon_task(tcx, dep_kinds::TraitSelect, || { - for _ in 0..FIXPOINT_STEP_LIMIT { - match self.fixpoint_step_in_task(tcx, input, inspect, &mut prove_goal) { - StepResult::Done(final_entry, result) => return (final_entry, result), - StepResult::HasChanged => debug!("fixpoint changed provisional results"), - } + let ((final_entry, result), dep_node) = tcx.with_cached_task(|| { + for _ in 0..FIXPOINT_STEP_LIMIT { + match self.fixpoint_step_in_task(tcx, input, inspect, &mut prove_goal) { + StepResult::Done(final_entry, result) => return (final_entry, result), + StepResult::HasChanged => debug!("fixpoint changed provisional results"), } + } - debug!("canonical cycle overflow"); - let current_entry = self.pop_stack(); - debug_assert!(current_entry.has_been_used.is_empty()); - let result = Self::response_no_constraints(tcx, input, Certainty::overflow(false)); - (current_entry, result) - }); + debug!("canonical cycle overflow"); + let current_entry = self.pop_stack(); + debug_assert!(current_entry.has_been_used.is_empty()); + let result = Self::response_no_constraints(tcx, input, Certainty::overflow(false)); + (current_entry, result) + }); let proof_tree = inspect.finalize_canonical_goal_evaluation(tcx); @@ -423,16 +411,17 @@ impl<'tcx> SearchGraph> { /// Try to fetch a previously computed result from the global cache, /// making sure to only do so if it would match the result of reevaluating /// this goal. - fn lookup_global_cache( + fn lookup_global_cache>( &mut self, - tcx: TyCtxt<'tcx>, - input: CanonicalInput>, - available_depth: Limit, - inspect: &mut ProofTreeBuilder>, - ) -> Option>> { + tcx: I, + input: CanonicalInput, + available_depth: SolverLimit, + inspect: &mut ProofTreeBuilder, + ) -> Option> { let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self .global_cache(tcx) - .get(tcx, input, self.stack.iter().map(|e| e.input), available_depth)?; + // FIXME: Awkward `Limit -> usize -> Limit`. + .get(tcx, input, self.stack.iter().map(|e| e.input), available_depth.0)?; // If we're building a proof tree and the current cache entry does not // contain a proof tree, we do not use the entry but instead recompute @@ -465,21 +454,22 @@ enum StepResult { HasChanged, } -impl<'tcx> SearchGraph> { +impl SearchGraph { /// When we encounter a coinductive cycle, we have to fetch the /// result of that cycle while we are still computing it. Because /// of this we continuously recompute the cycle until the result /// of the previous iteration is equal to the final result, at which /// point we are done. - fn fixpoint_step_in_task( + fn fixpoint_step_in_task( &mut self, - tcx: TyCtxt<'tcx>, - input: CanonicalInput>, - inspect: &mut ProofTreeBuilder>, + tcx: I, + input: CanonicalInput, + inspect: &mut ProofTreeBuilder, prove_goal: &mut F, - ) -> StepResult> + ) -> StepResult where - F: FnMut(&mut Self, &mut ProofTreeBuilder>) -> QueryResult>, + Infcx: SolverDelegate, + F: FnMut(&mut Self, &mut ProofTreeBuilder) -> QueryResult, { let result = prove_goal(self, inspect); let stack_entry = self.pop_stack(); @@ -533,15 +523,13 @@ impl<'tcx> SearchGraph> { } fn response_no_constraints( - tcx: TyCtxt<'tcx>, - goal: CanonicalInput>, + tcx: I, + goal: CanonicalInput, certainty: Certainty, - ) -> QueryResult> { + ) -> QueryResult { Ok(super::response_no_constraints_raw(tcx, goal.max_universe, goal.variables, certainty)) } -} -impl SearchGraph { #[allow(rustc::potential_query_instability)] fn check_invariants(&self) { if !cfg!(debug_assertions) { diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs similarity index 77% rename from compiler/rustc_trait_selection/src/solve/trait_goals.rs rename to compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index bcb2ea18f78e..d1419bf5db9a 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1,60 +1,60 @@ //! Dealing with trait goals, i.e. `T: Trait<'a, U>`. -use super::assembly::structural_traits::AsyncCallableRelevantTypes; -use super::assembly::{self, structural_traits, Candidate}; -use super::{EvalCtxt, GoalSource, SolverMode}; +use rustc_ast_ir::Movability; use rustc_data_structures::fx::FxIndexSet; -use rustc_hir::def_id::DefId; -use rustc_hir::{LangItem, Movability}; -use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::query::NoSolution; -use rustc_infer::traits::solve::MaybeCause; -use rustc_infer::traits::util::supertraits; -use rustc_middle::bug; -use rustc_middle::traits::solve::inspect::ProbeKind; -use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult}; -use rustc_middle::traits::{BuiltinImplSource, Reveal}; -use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; -use rustc_middle::ty::{TraitPredicate, TypeVisitableExt}; -use rustc_span::ErrorGuaranteed; +use rustc_type_ir::inherent::*; +use rustc_type_ir::lang_items::TraitSolverLangItem; +use rustc_type_ir::visit::TypeVisitableExt as _; +use rustc_type_ir::{self as ty, Interner, TraitPredicate, Upcast as _}; +use tracing::{instrument, trace}; -impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { - fn self_ty(self) -> Ty<'tcx> { +use crate::infcx::SolverDelegate; +use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes}; +use crate::solve::assembly::{self, Candidate}; +use crate::solve::inspect::ProbeKind; +use crate::solve::{ + BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause, + NoSolution, QueryResult, Reveal, SolverMode, +}; + +impl assembly::GoalKind for TraitPredicate +where + Infcx: SolverDelegate, + I: Interner, +{ + fn self_ty(self) -> I::Ty { self.self_ty() } - fn trait_ref(self, _: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { + fn trait_ref(self, _: I) -> ty::TraitRef { self.trait_ref } - fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { + fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self { self.with_self_ty(tcx, self_ty) } - fn trait_def_id(self, _: TyCtxt<'tcx>) -> DefId { + fn trait_def_id(self, _: I) -> I::DefId { self.def_id() } fn consider_impl_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, TraitPredicate<'tcx>>, - impl_def_id: DefId, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal>, + impl_def_id: I::DefId, + ) -> Result, NoSolution> { let tcx = ecx.interner(); - let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); - let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; - if !drcx.args_may_unify( - goal.predicate.trait_ref.args, - impl_trait_header.trait_ref.skip_binder().args, - ) { + let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); + if !tcx + .args_may_unify_deep(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args) + { return Err(NoSolution); } // An upper bound of the certainty of this goal, used to lower the certainty // of reservation impl to ambiguous during coherence. - let impl_polarity = impl_trait_header.polarity; + let impl_polarity = tcx.impl_polarity(impl_def_id); let maximal_certainty = match (impl_polarity, goal.predicate.polarity) { // In intercrate mode, this is ambiguous. But outside of intercrate, // it's not a real impl. @@ -77,14 +77,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| { let impl_args = ecx.fresh_args_for_item(impl_def_id); ecx.record_impl_args(impl_args); - let impl_trait_ref = impl_trait_header.trait_ref.instantiate(tcx, impl_args); + let impl_trait_ref = impl_trait_ref.instantiate(tcx, &impl_args); ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; let where_clause_bounds = tcx .predicates_of(impl_def_id) - .instantiate(tcx, impl_args) - .predicates - .into_iter() + .iter_instantiated(tcx, &impl_args) .map(|pred| goal.with(tcx, pred)); ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); @@ -93,21 +91,21 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_error_guaranteed_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - _guar: ErrorGuaranteed, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + _guar: I::ErrorGuaranteed, + ) -> Result, NoSolution> { // FIXME: don't need to enter a probe here. ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } fn probe_and_match_goal_against_assumption( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - source: CandidateSource<'tcx>, - goal: Goal<'tcx, Self>, - assumption: ty::Clause<'tcx>, - then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + source: CandidateSource, + goal: Goal, + assumption: I::Clause, + then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult, + ) -> Result, NoSolution> { if let Some(trait_clause) = assumption.as_trait_clause() { if trait_clause.def_id() == goal.predicate.def_id() && trait_clause.polarity() == goal.predicate.polarity @@ -130,9 +128,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_auto_trait_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -159,7 +157,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() { if matches!(goal.param_env.reveal(), Reveal::All) || matches!(ecx.solver_mode(), SolverMode::Coherence) - || ecx.can_define_opaque_ty(opaque_ty.def_id) + || opaque_ty + .def_id + .as_local() + .is_some_and(|def_id| ecx.can_define_opaque_ty(def_id)) { return Err(NoSolution); } @@ -173,9 +174,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_trait_alias_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -185,20 +186,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { let nested_obligations = tcx .predicates_of(goal.predicate.def_id()) - .instantiate(tcx, goal.predicate.trait_ref.args); + .iter_instantiated(tcx, &goal.predicate.trait_ref.args) + .map(|p| goal.with(tcx, p)); // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`? - ecx.add_goals( - GoalSource::Misc, - nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)), - ); + ecx.add_goals(GoalSource::Misc, nested_obligations); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } fn consider_builtin_sized_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -211,9 +210,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_copy_clone_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -226,28 +225,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_pointer_like_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } - // The regions of a type don't affect the size of the type let tcx = ecx.interner(); - // We should erase regions from both the param-env and type, since both - // may have infer regions. Specifically, after canonicalizing and instantiating, - // early bound regions turn into region vars in both the new and old solver. - let key = tcx.erase_regions(goal.param_env.and(goal.predicate.self_ty())); // But if there are inference variables, we have to wait until it's resolved. - if key.has_non_region_infer() { + if (goal.param_env, goal.predicate.self_ty()).has_non_region_infer() { return ecx.forced_ambiguity(MaybeCause::Ambiguity); } - if let Ok(layout) = tcx.layout_of(key) - && layout.layout.is_pointer_like(&tcx.data_layout) - { - // FIXME: We could make this faster by making a no-constraints response + if tcx.layout_is_pointer_like(goal.param_env, goal.predicate.self_ty()) { ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } else { @@ -256,9 +247,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_fn_ptr_trait_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); match goal.predicate.polarity { // impl FnPtr for FnPtr {} @@ -287,10 +278,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, goal_kind: ty::ClosureKind, - ) -> Result>, NoSolution> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -308,7 +299,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } }; let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { - ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output]) + ty::TraitRef::new(tcx, tcx.require_lang_item(TraitSolverLangItem::Sized), [output]) }); let pred = tupled_inputs_and_output @@ -328,10 +319,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_async_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, goal_kind: ty::ClosureKind, - ) -> Result>, NoSolution> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -343,13 +334,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal.predicate.self_ty(), goal_kind, // This region doesn't matter because we're throwing away the coroutine type - tcx.lifetimes.re_static, + Region::new_static(tcx), )?; let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| { ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Sized, None), + tcx.require_lang_item(TraitSolverLangItem::Sized), [output_coroutine_ty], ) }, @@ -379,11 +370,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_async_fn_kind_helper_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else { - bug!(); + panic!(); }; let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else { @@ -406,9 +397,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { /// impl Tuple for (T1, .., Tn) {} /// ``` fn consider_builtin_tuple_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -422,9 +413,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_pointee_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -434,14 +425,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_future_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } - let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else { + let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else { return Err(NoSolution); }; @@ -460,14 +451,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_iterator_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } - let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else { + let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else { return Err(NoSolution); }; @@ -486,14 +477,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_fused_iterator_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } - let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else { + let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else { return Err(NoSolution); }; @@ -510,14 +501,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_async_iterator_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } - let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else { + let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else { return Err(NoSolution); }; @@ -536,15 +527,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_coroutine_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } let self_ty = goal.predicate.self_ty(); - let ty::Coroutine(def_id, args) = *self_ty.kind() else { + let ty::Coroutine(def_id, args) = self_ty.kind() else { return Err(NoSolution); }; @@ -568,9 +559,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_discriminant_kind_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -581,9 +572,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_async_destruct_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -594,9 +585,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_destruct_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -610,9 +601,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_transmute_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -622,22 +613,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); } - // Erase regions because we compute layouts in `rustc_transmute`, - // which will ICE for region vars. - let args = ecx.interner().erase_regions(goal.predicate.trait_ref.args); - - let Some(assume) = - rustc_transmute::Assume::from_const(ecx.interner(), goal.param_env, args.const_at(2)) - else { - return Err(NoSolution); - }; - // FIXME: This actually should destructure the `Result` we get from transmutability and // register candiates. We probably need to register >1 since we may have an OR of ANDs. ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { let certainty = ecx.is_transmutable( - rustc_transmute::Types { dst: args.type_at(0), src: args.type_at(1) }, - assume, + goal.param_env, + goal.predicate.trait_ref.args.type_at(0), + goal.predicate.trait_ref.args.type_at(1), + goal.predicate.trait_ref.args.const_at(2), )?; ecx.evaluate_added_goals_and_make_canonical_response(certainty) }) @@ -651,9 +634,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { /// impl<'a, T: Trait + 'a> Unsize for T {} /// ``` fn consider_structural_builtin_unsize_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Vec>> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Vec> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return vec![]; } @@ -676,7 +659,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let goal = goal.with(ecx.interner(), (a_ty, b_ty)); match (a_ty.kind(), b_ty.kind()) { - (ty::Infer(ty::TyVar(..)), ..) => bug!("unexpected infer {a_ty:?} {b_ty:?}"), + (ty::Infer(ty::TyVar(..)), ..) => panic!("unexpected infer {a_ty:?} {b_ty:?}"), (_, ty::Infer(ty::TyVar(..))) => { result_to_single(ecx.forced_ambiguity(MaybeCause::Ambiguity)) @@ -684,24 +667,24 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`. ( - &ty::Dynamic(a_data, a_region, ty::Dyn), - &ty::Dynamic(b_data, b_region, ty::Dyn), + ty::Dynamic(a_data, a_region, ty::Dyn), + ty::Dynamic(b_data, b_region, ty::Dyn), ) => ecx.consider_builtin_dyn_upcast_candidates( goal, a_data, a_region, b_data, b_region, ), // `T` -> `dyn Trait` unsizing. - (_, &ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single( + (_, ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single( ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data), ), // `[T; N]` -> `[T]` unsizing - (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => { + (ty::Array(a_elem_ty, ..), ty::Slice(b_elem_ty)) => { result_to_single(ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty)) } // `Struct` -> `Struct` where `T: Unsize` - (&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args)) + (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args)) if a_def.is_struct() && a_def == b_def => { result_to_single( @@ -710,7 +693,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } // `(A, B, T)` -> `(A, B, U)` where `T: Unsize` - (&ty::Tuple(a_tys), &ty::Tuple(b_tys)) + (ty::Tuple(a_tys), ty::Tuple(b_tys)) if a_tys.len() == b_tys.len() && !a_tys.is_empty() => { result_to_single(ecx.consider_builtin_tuple_unsize(goal, a_tys, b_tys)) @@ -722,7 +705,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } } -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +impl EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ /// Trait upcasting allows for coercions between trait objects: /// ```ignore (builtin impl example) /// trait Super {} @@ -734,12 +721,12 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// ``` fn consider_builtin_dyn_upcast_candidates( &mut self, - goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, - a_data: &'tcx ty::List>, - a_region: ty::Region<'tcx>, - b_data: &'tcx ty::List>, - b_region: ty::Region<'tcx>, - ) -> Vec>> { + goal: Goal, + a_data: I::BoundExistentialPredicates, + a_region: I::Region, + b_data: I::BoundExistentialPredicates, + b_region: I::Region, + ) -> Vec> { let tcx = self.interner(); let Goal { predicate: (a_ty, _b_ty), .. } = goal; @@ -757,7 +744,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { a_data.principal(), )); } else if let Some(a_principal) = a_data.principal() { - for new_a_principal in supertraits(tcx, a_principal.with_self_ty(tcx, a_ty)).skip(1) { + for new_a_principal in + Infcx::elaborate_supertraits(self.interner(), a_principal.with_self_ty(tcx, a_ty)) + .skip(1) + { responses.extend(self.consider_builtin_upcast_to_principal( goal, CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting), @@ -777,15 +767,15 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn consider_builtin_unsize_to_dyn_candidate( &mut self, - goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, - b_data: &'tcx ty::List>, - b_region: ty::Region<'tcx>, - ) -> Result>, NoSolution> { + goal: Goal, + b_data: I::BoundExistentialPredicates, + b_region: I::Region, + ) -> Result, NoSolution> { let tcx = self.interner(); let Goal { predicate: (a_ty, _), .. } = goal; // Can only unsize to an object-safe trait. - if b_data.principal_def_id().is_some_and(|def_id| !tcx.is_object_safe(def_id)) { + if b_data.principal_def_id().is_some_and(|def_id| !tcx.trait_is_object_safe(def_id)) { return Err(NoSolution); } @@ -794,7 +784,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // (i.e. the principal, all of the associated types match, and any auto traits) ecx.add_goals( GoalSource::ImplWhereBound, - b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), + b_data.into_iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), ); // The type must be `Sized` to be unsized. @@ -802,7 +792,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { GoalSource::ImplWhereBound, goal.with( tcx, - ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [a_ty]), + ty::TraitRef::new( + tcx, + tcx.require_lang_item(TraitSolverLangItem::Sized), + [a_ty], + ), ), ); @@ -814,24 +808,26 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn consider_builtin_upcast_to_principal( &mut self, - goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, - source: CandidateSource<'tcx>, - a_data: &'tcx ty::List>, - a_region: ty::Region<'tcx>, - b_data: &'tcx ty::List>, - b_region: ty::Region<'tcx>, - upcast_principal: Option>, - ) -> Result>, NoSolution> { + goal: Goal, + source: CandidateSource, + a_data: I::BoundExistentialPredicates, + a_region: I::Region, + b_data: I::BoundExistentialPredicates, + b_region: I::Region, + upcast_principal: Option>>, + ) -> Result, NoSolution> { let param_env = goal.param_env; // We may upcast to auto traits that are either explicitly listed in // the object type's bounds, or implied by the principal trait ref's // supertraits. - let a_auto_traits: FxIndexSet = a_data + let a_auto_traits: FxIndexSet = a_data .auto_traits() + .into_iter() .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { self.interner() .supertrait_def_ids(principal_def_id) + .into_iter() .filter(|def_id| self.interner().trait_is_auto(*def_id)) })) .collect(); @@ -841,9 +837,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // having any inference side-effects. We process obligations because // unification may initially succeed due to deferred projection equality. let projection_may_match = - |ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - source_projection: ty::PolyExistentialProjection<'tcx>, - target_projection: ty::PolyExistentialProjection<'tcx>| { + |ecx: &mut EvalCtxt<'_, Infcx>, + source_projection: ty::Binder>, + target_projection: ty::Binder>| { source_projection.item_def_id() == target_projection.item_def_id() && ecx .probe(|_| ProbeKind::UpcastProjectionCompatibility) @@ -875,7 +871,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ty::ExistentialPredicate::Projection(target_projection) => { let target_projection = bound.rebind(target_projection); let mut matching_projections = - a_data.projection_bounds().filter(|source_projection| { + a_data.projection_bounds().into_iter().filter(|source_projection| { projection_may_match(ecx, *source_projection, target_projection) }); let Some(source_projection) = matching_projections.next() else { @@ -900,11 +896,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // Also require that a_ty's lifetime outlives b_ty's lifetime. ecx.add_goal( GoalSource::ImplWhereBound, - Goal::new( - ecx.interner(), - param_env, - ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)), - ), + Goal::new(ecx.interner(), param_env, ty::OutlivesPredicate(a_region, b_region)), ); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) @@ -921,10 +913,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// `#[rustc_deny_explicit_impl]` in this case. fn consider_builtin_array_unsize( &mut self, - goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, - a_elem_ty: Ty<'tcx>, - b_elem_ty: Ty<'tcx>, - ) -> Result>, NoSolution> { + goal: Goal, + a_elem_ty: I::Ty, + b_elem_ty: I::Ty, + ) -> Result, NoSolution> { self.eq(goal.param_env, a_elem_ty, b_elem_ty)?; self.probe_builtin_trait_candidate(BuiltinImplSource::Misc) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) @@ -945,26 +937,25 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// ``` fn consider_builtin_struct_unsize( &mut self, - goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, - def: ty::AdtDef<'tcx>, - a_args: ty::GenericArgsRef<'tcx>, - b_args: ty::GenericArgsRef<'tcx>, - ) -> Result>, NoSolution> { + goal: Goal, + def: I::AdtDef, + a_args: I::GenericArgs, + b_args: I::GenericArgs, + ) -> Result, NoSolution> { let tcx = self.interner(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; - let unsizing_params = tcx.unsizing_params_for_adt(def.did()); + let unsizing_params = tcx.unsizing_params_for_adt(def.def_id()); // We must be unsizing some type parameters. This also implies // that the struct has a tail field. if unsizing_params.is_empty() { return Err(NoSolution); } - let tail_field = def.non_enum_variant().tail(); - let tail_field_ty = tcx.type_of(tail_field.did); + let tail_field_ty = def.struct_tail_ty(tcx).unwrap(); - let a_tail_ty = tail_field_ty.instantiate(tcx, a_args); - let b_tail_ty = tail_field_ty.instantiate(tcx, b_args); + let a_tail_ty = tail_field_ty.instantiate(tcx, &a_args); + let b_tail_ty = tail_field_ty.instantiate(tcx, &b_args); // Instantiate just the unsizing params from B into A. The type after // this instantiation must be equal to B. This is so we don't unsize @@ -973,7 +964,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { a_args .iter() .enumerate() - .map(|(i, a)| if unsizing_params.contains(i as u32) { b_args[i] } else { a }), + .map(|(i, a)| if unsizing_params.contains(i as u32) { b_args[i] } else { *a }), ); let unsized_a_ty = Ty::new_adt(tcx, def, new_a_args); @@ -986,7 +977,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { tcx, ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Unsize, None), + tcx.require_lang_item(TraitSolverLangItem::Unsize), [a_tail_ty, b_tail_ty], ), ), @@ -1007,10 +998,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// ``` fn consider_builtin_tuple_unsize( &mut self, - goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, - a_tys: &'tcx ty::List>, - b_tys: &'tcx ty::List>, - ) -> Result>, NoSolution> { + goal: Goal, + a_tys: I::Tys, + b_tys: I::Tys, + ) -> Result, NoSolution> { let tcx = self.interner(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; @@ -1029,7 +1020,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { tcx, ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Unsize, None), + tcx.require_lang_item(TraitSolverLangItem::Unsize), [a_last_ty, b_last_ty], ), ), @@ -1044,10 +1035,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // the type's constituent types. fn disqualify_auto_trait_candidate_due_to_possible_impl( &mut self, - goal: Goal<'tcx, TraitPredicate<'tcx>>, - ) -> Option>, NoSolution>> { + goal: Goal>, + ) -> Option, NoSolution>> { let self_ty = goal.predicate.self_ty(); - match *self_ty.kind() { + match self_ty.kind() { // Stall int and float vars until they are resolved to a concrete // numerical type. That's because the check for impls below treats // int vars as matching any impl. Even if we filtered such impls, @@ -1065,13 +1056,15 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { | ty::Alias(ty::Projection | ty::Weak | ty::Inherent, ..) | ty::Placeholder(..) => Some(Err(NoSolution)), - ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"), + ty::Infer(_) | ty::Bound(_, _) => panic!("unexpected type `{self_ty:?}`"), // Coroutines have one special built-in candidate, `Unpin`, which // takes precedence over the structural auto trait candidate being // assembled. ty::Coroutine(def_id, _) - if self.interner().is_lang_item(goal.predicate.def_id(), LangItem::Unpin) => + if self + .interner() + .is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::Unpin) => { match self.interner().coroutine_movability(def_id) { Movability::Static => Some(Err(NoSolution)), @@ -1144,13 +1137,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// wrapped in one. fn probe_and_evaluate_goal_for_constituent_tys( &mut self, - source: CandidateSource<'tcx>, - goal: Goal<'tcx, TraitPredicate<'tcx>>, + source: CandidateSource, + goal: Goal>, constituent_tys: impl Fn( - &EvalCtxt<'_, InferCtxt<'tcx>>, - Ty<'tcx>, - ) -> Result>>, NoSolution>, - ) -> Result>, NoSolution> { + &EvalCtxt<'_, Infcx>, + I::Ty, + ) -> Result>, NoSolution>, + ) -> Result, NoSolution> { self.probe_trait_candidate(source).enter(|ecx| { ecx.add_goals( GoalSource::ImplWhereBound, @@ -1173,8 +1166,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self))] pub(super) fn compute_trait_goal( &mut self, - goal: Goal<'tcx, TraitPredicate<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal>, + ) -> QueryResult { let candidates = self.assemble_and_evaluate_candidates(goal); self.merge_candidates(candidates) } diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 6c1fcbe06fc5..7566a4d50662 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use rustc_ast::token::Token; use rustc_ast::{Path, Visibility}; use rustc_errors::{ - codes::*, Applicability, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, + codes::*, Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, SubdiagMessageOp, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -1052,7 +1052,7 @@ pub(crate) struct ExpectedIdentifier { impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedIdentifier { #[track_caller] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let token_descr = TokenDescription::from_token(&self.token); let mut diag = Diag::new( @@ -1112,7 +1112,7 @@ pub(crate) struct ExpectedSemi { impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi { #[track_caller] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let token_descr = TokenDescription::from_token(&self.token); let mut diag = Diag::new( diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 43f4963b27ac..511805cf8d6e 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -7,7 +7,7 @@ use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::unicode::contains_text_flow_control_chars; -use rustc_errors::{codes::*, Applicability, Diag, DiagCtxt, StashKey}; +use rustc_errors::{codes::*, Applicability, Diag, DiagCtxtHandle, StashKey}; use rustc_lexer::unescape::{self, EscapeError, Mode}; use rustc_lexer::{Base, DocStyle, RawStrError}; use rustc_lexer::{Cursor, LiteralKind}; @@ -113,8 +113,8 @@ struct StringReader<'psess, 'src> { } impl<'psess, 'src> StringReader<'psess, 'src> { - fn dcx(&self) -> &'psess DiagCtxt { - &self.psess.dcx + fn dcx(&self) -> DiagCtxtHandle<'psess> { + self.psess.dcx() } fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span { @@ -248,8 +248,8 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let suffix = if suffix_start < self.pos { let string = self.str_from(suffix_start); if string == "_" { - self.psess - .dcx + self + .dcx() .emit_err(errors::UnderscoreLiteralSuffix { span: self.mk_sp(suffix_start, self.pos) }); None } else { @@ -597,8 +597,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { } fn report_non_started_raw_string(&self, start: BytePos, bad_char: char) -> ! { - self.psess - .dcx + self.dcx() .struct_span_fatal( self.mk_sp(start, self.pos), format!( diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index f7645446081a..8e5434546913 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -71,7 +71,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { fn eof_err(&mut self) -> PErr<'psess> { let msg = "this file contains an unclosed delimiter"; - let mut err = self.string_reader.psess.dcx.struct_span_err(self.token.span, msg); + let mut err = self.string_reader.dcx().struct_span_err(self.token.span, msg); for &(_, sp) in &self.diag_info.open_braces { err.span_label(sp, "unclosed delimiter"); self.diag_info.unmatched_delims.push(UnmatchedDelim { @@ -290,7 +290,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { // An unexpected closing delimiter (i.e., there is no matching opening delimiter). let token_str = token_to_string(&self.token); let msg = format!("unexpected closing delimiter: `{token_str}`"); - let mut err = self.string_reader.psess.dcx.struct_span_err(self.token.span, msg); + let mut err = self.string_reader.dcx().struct_span_err(self.token.span, msg); report_suspicious_mismatch_block( &mut err, diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index cad25c66827b..b7a790fcf83a 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -3,7 +3,7 @@ use std::iter::once; use std::ops::Range; -use rustc_errors::{Applicability, DiagCtxt, ErrorGuaranteed}; +use rustc_errors::{Applicability, DiagCtxtHandle, ErrorGuaranteed}; use rustc_lexer::unescape::{EscapeError, Mode}; use rustc_span::{BytePos, Span}; use tracing::debug; @@ -11,7 +11,7 @@ use tracing::debug; use crate::errors::{MoreThanOneCharNote, MoreThanOneCharSugg, NoBraceUnicodeSub, UnescapeError}; pub(crate) fn emit_unescape_error( - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, // interior part of the literal, between quotes lit: &str, // full span of the literal, including quotes and any prefix diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index 8eb299108d10..0a82ede3b75d 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -351,7 +351,7 @@ pub(super) fn check_for_substitution( let Some((_, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(s, _, _)| s == ascii_str) else { let msg = format!("substitution character not found for '{ch}'"); - reader.psess.dcx.span_bug(span, msg); + reader.dcx().span_bug(span, msg); }; // special help suggestion for "directed" double quotes diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 25cab7252a36..5522127be83e 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -73,7 +73,7 @@ pub fn new_parser_from_file<'a>( ) -> Result, Vec>> { let source_file = psess.source_map().load_file(path).unwrap_or_else(|e| { let msg = format!("couldn't read {}: {}", path.display(), e); - let mut err = psess.dcx.struct_fatal(msg); + let mut err = psess.dcx().struct_fatal(msg); if let Some(sp) = sp { err.span(sp); } @@ -115,7 +115,7 @@ fn source_file_to_stream<'psess>( override_span: Option, ) -> Result>> { let src = source_file.src.as_ref().unwrap_or_else(|| { - psess.dcx.bug(format!( + psess.dcx().bug(format!( "cannot lex `source_file` without source: {}", psess.source_map().filename_for_diagnostics(&source_file.name) )); @@ -179,7 +179,7 @@ pub fn parse_cfg_attr( } } _ => { - psess.dcx.emit_err(errors::MalformedCfgAttr { + psess.dcx().emit_err(errors::MalformedCfgAttr { span: attr.span, sugg: CFG_ATTR_GRAMMAR_HELP, }); diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 62c8f9f5dacb..f5c931034fd2 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -41,7 +41,7 @@ impl AttrWrapper { } pub(crate) fn take_for_recovery(self, psess: &ParseSess) -> AttrVec { - psess.dcx.span_delayed_bug( + psess.dcx().span_delayed_bug( self.attrs.get(0).map(|attr| attr.span).unwrap_or(DUMMY_SP), "AttrVec is taken for recovery but no error is produced", ); diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 2bb6fb53869b..c1aac84bcaec 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1,7 +1,6 @@ use super::pat::Expected; use super::{ - BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, - TokenExpectType, TokenType, + BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenType, }; use crate::errors::{ AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, BadQPathStage2, BadTypePlus, @@ -35,7 +34,7 @@ use rustc_ast::{ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - pluralize, Applicability, Diag, DiagCtxt, ErrorGuaranteed, FatalError, PErr, PResult, + pluralize, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, PErr, PResult, Subdiagnostic, }; use rustc_session::errors::ExprParenthesesNeeded; @@ -241,8 +240,8 @@ impl<'a> DerefMut for SnapshotParser<'a> { } impl<'a> Parser<'a> { - pub fn dcx(&self) -> &'a DiagCtxt { - &self.psess.dcx + pub fn dcx(&self) -> DiagCtxtHandle<'a> { + self.psess.dcx() } /// Replace `self` with `snapshot.parser`. @@ -667,7 +666,7 @@ impl<'a> Parser<'a> { { err.note("you may be trying to write a c-string literal"); err.note("c-string literals require Rust 2021 or later"); - err.subdiagnostic(self.dcx(), HelpUseLatestEdition::new()); + err.subdiagnostic(HelpUseLatestEdition::new()); } // `pub` may be used for an item or `pub(crate)` @@ -1045,9 +1044,7 @@ impl<'a> Parser<'a> { /// passes through any errors encountered. Used for error recovery. pub(super) fn eat_to_tokens(&mut self, kets: &[&TokenKind]) { if let Err(err) = - self.parse_seq_to_before_tokens(kets, SeqSep::none(), TokenExpectType::Expect, |p| { - Ok(p.parse_token_tree()) - }) + self.parse_seq_to_before_tokens(kets, &[], SeqSep::none(), |p| Ok(p.parse_token_tree())) { err.cancel(); } @@ -2360,7 +2357,7 @@ impl<'a> Parser<'a> { let mut err = self.dcx().struct_span_err(span, msg); let sp = self.psess.source_map().start_point(self.token.span); if let Some(sp) = self.psess.ambiguous_block_expr_parse.borrow().get(&sp) { - err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp)); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } err.span_label(span, "expected expression"); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e15d6ab2123a..5decfc142dac 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -4,7 +4,7 @@ use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{ AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions, - SemiColonMode, SeqSep, TokenExpectType, TokenType, Trailing, TrailingToken, + SemiColonMode, SeqSep, TokenType, Trailing, TrailingToken, }; use crate::errors; @@ -1461,7 +1461,7 @@ impl<'a> Parser<'a> { // If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }` // then suggest parens around the lhs. if let Some(sp) = this.psess.ambiguous_block_expr_parse.borrow().get(&lo) { - err.subdiagnostic(this.dcx(), ExprParenthesesNeeded::surrounding(*sp)); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } err }) @@ -2456,9 +2456,9 @@ impl<'a> Parser<'a> { self.expect(&token::BinOp(token::Or))?; let args = self .parse_seq_to_before_tokens( - &[&token::BinOp(token::Or), &token::OrOr], + &[&token::BinOp(token::Or)], + &[&token::OrOr], SeqSep::trailing_allowed(token::Comma), - TokenExpectType::NoExpect, |p| p.parse_fn_block_param(), )? .0; diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 93a15c938ecf..fde16ac957df 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -62,7 +62,7 @@ impl<'a> Parser<'a> { let snapshot = self.create_snapshot_for_diagnostic(); match self.parse_ty() { Ok(p) => { - if let TyKind::ImplTrait(_, bounds, None) = &p.kind { + if let TyKind::ImplTrait(_, bounds) = &p.kind { let span = impl_span.to(self.token.span.shrink_to_lo()); let mut err = self.dcx().struct_span_err( span, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 3f5a4afdad8a..42f8c6e38b92 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -633,7 +633,7 @@ impl<'a> Parser<'a> { // This notably includes paths passed through `ty` macro fragments (#46438). TyKind::Path(None, path) => path, other => { - if let TyKind::ImplTrait(_, bounds, None) = other + if let TyKind::ImplTrait(_, bounds) = other && let [bound] = bounds.as_slice() { // Suggest removing extra `impl` keyword: @@ -1966,7 +1966,7 @@ impl<'a> Parser<'a> { if self.token.kind == token::Not { if let Err(mut err) = self.unexpected() { // Encounter the macro invocation - err.subdiagnostic(self.dcx(), MacroExpandsToAdtField { adt_ty }); + err.subdiagnostic(MacroExpandsToAdtField { adt_ty }); return Err(err); } } @@ -2382,13 +2382,10 @@ impl<'a> Parser<'a> { .into_iter() .any(|s| self.prev_token.is_ident_named(s)); - err.subdiagnostic( - self.dcx(), - errors::FnTraitMissingParen { - span: self.prev_token.span, - machine_applicable, - }, - ); + err.subdiagnostic(errors::FnTraitMissingParen { + span: self.prev_token.span, + machine_applicable, + }); } return Err(err); } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index adf04fcf2241..6dee913c1416 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -335,18 +335,6 @@ impl TokenType { } } -/// Used by [`Parser::expect_any_with_type`]. -#[derive(Copy, Clone, Debug)] -enum TokenExpectType { - /// Unencountered tokens are inserted into [`Parser::expected_tokens`]. - /// See [`Parser::check`]. - Expect, - - /// Unencountered tokens are not inserted into [`Parser::expected_tokens`]. - /// See [`Parser::check_noexpect`]. - NoExpect, -} - /// A sequence separator. #[derive(Debug)] struct SeqSep { @@ -807,11 +795,13 @@ impl<'a> Parser<'a> { } /// Checks if the next token is contained within `kets`, and returns `true` if so. - fn expect_any_with_type(&mut self, kets: &[&TokenKind], expect: TokenExpectType) -> bool { - kets.iter().any(|k| match expect { - TokenExpectType::Expect => self.check(k), - TokenExpectType::NoExpect => self.check_noexpect(k), - }) + fn expect_any_with_type( + &mut self, + kets_expected: &[&TokenKind], + kets_not_expected: &[&TokenKind], + ) -> bool { + kets_expected.iter().any(|k| self.check(k)) + || kets_not_expected.iter().any(|k| self.check_noexpect(k)) } /// Parses a sequence until the specified delimiters. The function @@ -819,9 +809,9 @@ impl<'a> Parser<'a> { /// closing bracket. fn parse_seq_to_before_tokens( &mut self, - kets: &[&TokenKind], + kets_expected: &[&TokenKind], + kets_not_expected: &[&TokenKind], sep: SeqSep, - expect: TokenExpectType, mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, (ThinVec, Trailing, Recovered)> { let mut first = true; @@ -829,7 +819,7 @@ impl<'a> Parser<'a> { let mut trailing = Trailing::No; let mut v = ThinVec::new(); - while !self.expect_any_with_type(kets, expect) { + while !self.expect_any_with_type(kets_expected, kets_not_expected) { if let token::CloseDelim(..) | token::Eof = self.token.kind { break; } @@ -927,7 +917,8 @@ impl<'a> Parser<'a> { if self.token == token::Colon { // we will try to recover in `maybe_recover_struct_lit_bad_delims` return Err(expect_err); - } else if let [token::CloseDelim(Delimiter::Parenthesis)] = kets + } else if let [token::CloseDelim(Delimiter::Parenthesis)] = + kets_expected { return Err(expect_err); } else { @@ -940,7 +931,9 @@ impl<'a> Parser<'a> { } } } - if sep.trailing_sep_allowed && self.expect_any_with_type(kets, expect) { + if sep.trailing_sep_allowed + && self.expect_any_with_type(kets_expected, kets_not_expected) + { trailing = Trailing::Yes; break; } @@ -1020,7 +1013,7 @@ impl<'a> Parser<'a> { sep: SeqSep, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, (ThinVec, Trailing, Recovered)> { - self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f) + self.parse_seq_to_before_tokens(&[ket], &[], sep, f) } /// Parses a sequence, including only the closing delimiter. The function @@ -1603,7 +1596,7 @@ pub(crate) fn make_unclosed_delims_error( if let Some(sp) = unmatched.unclosed_span { spans.push(sp); }; - let err = psess.dcx.create_err(MismatchedClosingDelimiter { + let err = psess.dcx().create_err(MismatchedClosingDelimiter { spans, delimiter: pprust::token_kind_to_string(&token::CloseDelim(found_delim)).to_string(), unmatched: unmatched.found_span, diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 8af415f7c9dd..f7f06ab7cbdd 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -851,7 +851,7 @@ impl<'a> Parser<'a> { let sp = self.psess.source_map().start_point(self.token.span); if let Some(sp) = self.psess.ambiguous_block_expr_parse.borrow().get(&sp) { - err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp)); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } Err(err) diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 79a6cf1b541e..3a4690670af3 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -61,7 +61,7 @@ where { let mut p = string_to_parser(&psess, s); let x = f(&mut p).unwrap(); - p.psess.dcx.abort_if_errors(); + p.dcx().abort_if_errors(); x } @@ -193,7 +193,7 @@ impl Write for Shared { #[allow(rustc::untranslatable_diagnostic)] // no translation needed for tests fn test_harness(file_text: &str, span_labels: Vec, expected_output: &str) { create_default_session_globals_then(|| { - let (handler, source_map, output) = create_test_handler(); + let (dcx, source_map, output) = create_test_handler(); source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned()); let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end); @@ -205,7 +205,7 @@ fn test_harness(file_text: &str, span_labels: Vec, expected_output: & println!("text: {:?}", source_map.span_to_snippet(span)); } - handler.span_err(msp, "foo"); + dcx.handle().span_err(msp, "foo"); assert!( expected_output.chars().next() == Some('\n'), diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 5bed0317e5eb..fcd623b477f5 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -9,7 +9,7 @@ use crate::errors::{ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Token, TokenKind}; +use rustc_ast::token::{self, BinOpToken, Delimiter, Token, TokenKind}; use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, FnRetTy, GenericBound, @@ -316,7 +316,7 @@ impl<'a> Parser<'a> { TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn) } (TyKind::TraitObject(bounds, _), kw::Impl) => { - TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds, None) + TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds) } _ => return Err(err), }; @@ -670,33 +670,26 @@ impl<'a> Parser<'a> { }) } - // parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of - // lifetimes and ident params (including SelfUpper). These are validated later - // for order, duplication, and whether they actually reference params. - let precise_capturing = if self.eat_keyword(kw::Use) { - let use_span = self.prev_token.span; - self.psess.gated_spans.gate(sym::precise_capturing, use_span); - let (args, args_span) = self.parse_precise_capturing_args()?; - Some(P((args, use_span.to(args_span)))) - } else { - None - }; - // Always parse bounds greedily for better error recovery. let bounds = self.parse_generic_bounds()?; *impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus); - Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds, precise_capturing)) + Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)) } fn parse_precise_capturing_args( &mut self, ) -> PResult<'a, (ThinVec, Span)> { let lo = self.token.span; - let (args, _) = self.parse_unspanned_seq( - &TokenKind::Lt, - &TokenKind::Gt, + self.expect_lt()?; + let (args, _, _) = self.parse_seq_to_before_tokens( + &[&TokenKind::Gt], + &[ + &TokenKind::Ge, + &TokenKind::BinOp(BinOpToken::Shr), + &TokenKind::BinOpEq(BinOpToken::Shr), + ], SeqSep::trailing_allowed(token::Comma), |self_| { if self_.check_keyword(kw::SelfUpper) { @@ -717,6 +710,7 @@ impl<'a> Parser<'a> { } }, )?; + self.expect_gt()?; Ok((args, lo.to(self.prev_token.span))) } @@ -828,6 +822,7 @@ impl<'a> Parser<'a> { || self.check(&token::OpenDelim(Delimiter::Parenthesis)) || self.check_keyword(kw::Const) || self.check_keyword(kw::Async) + || self.check_keyword(kw::Use) } /// Parses a bound according to the grammar: @@ -844,6 +839,14 @@ impl<'a> Parser<'a> { let bound = if self.token.is_lifetime() { self.error_lt_bound_with_modifiers(modifiers); self.parse_generic_lt_bound(lo, inner_lo, has_parens)? + } else if self.eat_keyword(kw::Use) { + // parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of + // lifetimes and ident params (including SelfUpper). These are validated later + // for order, duplication, and whether they actually reference params. + let use_span = self.prev_token.span; + self.psess.gated_spans.gate(sym::precise_capturing, use_span); + let (args, args_span) = self.parse_precise_capturing_args()?; + GenericBound::Use(args, use_span.to(args_span)) } else { self.parse_generic_ty_bound(lo, has_parens, modifiers, &leading_token)? }; @@ -1003,7 +1006,7 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ) } - TyKind::ImplTrait(_, bounds, None) + TyKind::ImplTrait(_, bounds) if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() => { ( diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 19d6f512572f..4ca52146039c 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -65,7 +65,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met let res = match res { Ok(lit) => { if token_lit.suffix.is_some() { - let mut err = psess.dcx.struct_span_err( + let mut err = psess.dcx().struct_span_err( expr.span, "suffixed literals are not allowed in attributes", ); @@ -98,7 +98,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met // the error because an earlier error will have already // been reported. let msg = "attribute value must be a literal"; - let mut err = psess.dcx.struct_span_err(expr.span, msg); + let mut err = psess.dcx().struct_span_err(expr.span, msg); if let ast::ExprKind::Err(_) = expr.kind { err.downgrade_to_delayed_bug(); } @@ -114,7 +114,7 @@ fn check_meta_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) { if let Delimiter::Parenthesis = delim { return; } - psess.dcx.emit_err(errors::MetaBadDelim { + psess.dcx().emit_err(errors::MetaBadDelim { span: span.entire(), sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close }, }); @@ -124,7 +124,7 @@ pub(super) fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim if let Delimiter::Parenthesis = delim { return; } - psess.dcx.emit_err(errors::CfgAttrBadDelim { + psess.dcx().emit_err(errors::CfgAttrBadDelim { span: span.entire(), sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close }, }); @@ -191,7 +191,7 @@ fn emit_malformed_attribute( } else { suggestions.sort(); psess - .dcx + .dcx() .struct_span_err(span, error_msg) .with_span_suggestions( span, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 6ce7c41acc8f..a0b3470df6db 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -8,8 +8,8 @@ use crate::{errors, fluent_generated as fluent}; use rustc_ast::{ast, AttrKind, AttrStyle, Attribute, LitKind}; use rustc_ast::{MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::StashKey; -use rustc_errors::{Applicability, DiagCtxt, IntoDiagArg, MultiSpan}; +use rustc_errors::{Applicability, IntoDiagArg, MultiSpan}; +use rustc_errors::{DiagCtxtHandle, StashKey}; use rustc_feature::{ is_unsafe_attr, AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP, }; @@ -99,7 +99,7 @@ struct CheckAttrVisitor<'tcx> { } impl<'tcx> CheckAttrVisitor<'tcx> { - fn dcx(&self) -> &'tcx DiagCtxt { + fn dcx(&self) -> DiagCtxtHandle<'tcx> { self.tcx.dcx() } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index a935f1ad7d35..25df80d5a92c 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -6,8 +6,8 @@ use std::{ use crate::fluent_generated as fluent; use rustc_ast::{ast, Label}; use rustc_errors::{ - codes::*, Applicability, Diag, DiagCtxt, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, - MultiSpan, SubdiagMessageOp, Subdiagnostic, + codes::*, Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, + Level, MultiSpan, SubdiagMessageOp, Subdiagnostic, }; use rustc_hir::{self as hir, ExprKind, Target}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -880,7 +880,7 @@ pub struct ItemFollowingInnerAttr { impl Diagnostic<'_, G> for InvalidAttrAtCrateLevel { #[track_caller] - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::passes_invalid_attr_at_crate_level); diag.span(self.span); diag.arg("name", self.name); @@ -1030,7 +1030,7 @@ pub struct BreakNonLoop<'a> { impl<'a, G: EmissionGuarantee> Diagnostic<'_, G> for BreakNonLoop<'a> { #[track_caller] - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::passes_break_non_loop); diag.span(self.span); diag.code(E0571); @@ -1176,7 +1176,7 @@ pub struct NakedFunctionsAsmBlock { impl Diagnostic<'_, G> for NakedFunctionsAsmBlock { #[track_caller] - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::passes_naked_functions_asm_block); diag.span(self.span); diag.code(E0787); @@ -1264,7 +1264,7 @@ pub struct NoMainErr { impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NoMainErr { #[track_caller] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut diag = Diag::new(dcx, level, fluent::passes_no_main_function); diag.span(DUMMY_SP); diag.code(E0601); @@ -1322,7 +1322,7 @@ pub struct DuplicateLangItem { impl Diagnostic<'_, G> for DuplicateLangItem { #[track_caller] - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new( dcx, level, diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index d49298781a23..0ba61f8e8b40 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -429,7 +429,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { fn visit_param_bound(&mut self, b: &'v hir::GenericBound<'v>) { record_variants!( (self, b, b, Id::None, hir, GenericBound, GenericBound), - [Trait, Outlives] + [Trait, Outlives, Use] ); hir_visit::walk_param_bound(self, b) } @@ -659,7 +659,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { fn visit_param_bound(&mut self, b: &'v ast::GenericBound, _ctxt: BoundKind) { record_variants!( (self, b, b, Id::None, ast, GenericBound, GenericBound), - [Trait, Outlives] + [Trait, Outlives, Use] ); ast_visit::walk_param_bound(self, b) } diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 248a741af907..3f44b11850e5 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -4,7 +4,7 @@ use crate::query::plumbing::CycleError; use crate::query::DepKind; use crate::query::{QueryContext, QueryStackFrame}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{Diag, DiagCtxt}; +use rustc_errors::{Diag, DiagCtxtHandle}; use rustc_hir::def::DefKind; use rustc_session::Session; use rustc_span::Span; @@ -600,7 +600,7 @@ pub fn report_cycle<'a>( pub fn print_query_stack( qcx: Qcx, mut current_query: Option, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, num_frames: Option, mut file: Option, ) -> usize { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 8d470c6c61ef..263daa11ec31 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -6,7 +6,7 @@ use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - codes::*, report_ambiguity_error, struct_span_code_err, Applicability, Diag, DiagCtxt, + codes::*, report_ambiguity_error, struct_span_code_err, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle, }; use rustc_feature::BUILTIN_ATTRIBUTES; @@ -120,7 +120,7 @@ fn reduce_impl_span_to_impl_keyword(sm: &SourceMap, impl_span: Span) -> Span { } impl<'a, 'tcx> Resolver<'a, 'tcx> { - pub(crate) fn dcx(&self) -> &'tcx DiagCtxt { + pub(crate) fn dcx(&self) -> DiagCtxtHandle<'tcx> { self.tcx.dcx() } @@ -334,12 +334,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Some((import, _, true)) if should_remove_import && !import.is_glob() => { // Simple case - remove the entire import. Due to the above match arm, this can // only be a single use so just remove it entirely. - err.subdiagnostic( - self.tcx.dcx(), - errors::ToolOnlyRemoveUnnecessaryImport { - span: import.use_span_with_attributes, - }, - ); + err.subdiagnostic(errors::ToolOnlyRemoveUnnecessaryImport { + span: import.use_span_with_attributes, + }); } Some((import, span, _)) => { self.add_suggestion_for_rename_of_use(&mut err, name, import, span); @@ -405,12 +402,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if let Some(suggestion) = suggestion { - err.subdiagnostic( - self.dcx(), - ChangeImportBindingSuggestion { span: binding_span, suggestion }, - ); + err.subdiagnostic(ChangeImportBindingSuggestion { span: binding_span, suggestion }); } else { - err.subdiagnostic(self.dcx(), ChangeImportBinding { span: binding_span }); + err.subdiagnostic(ChangeImportBinding { span: binding_span }); } } @@ -458,20 +452,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // previous imports. if found_closing_brace { if let Some(span) = extend_span_to_previous_binding(self.tcx.sess, span) { - err.subdiagnostic(self.dcx(), errors::ToolOnlyRemoveUnnecessaryImport { span }); + err.subdiagnostic(errors::ToolOnlyRemoveUnnecessaryImport { span }); } else { // Remove the entire line if we cannot extend the span back, this indicates an // `issue_52891::{self}` case. - err.subdiagnostic( - self.dcx(), - errors::RemoveUnnecessaryImport { span: import.use_span_with_attributes }, - ); + err.subdiagnostic(errors::RemoveUnnecessaryImport { + span: import.use_span_with_attributes, + }); } return; } - err.subdiagnostic(self.dcx(), errors::RemoveUnnecessaryImport { span }); + err.subdiagnostic(errors::RemoveUnnecessaryImport { span }); } pub(crate) fn lint_if_path_starts_with_module( @@ -682,10 +675,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .dcx() .create_err(errors::VariableIsNotBoundInAllPatterns { multispan: msp, name }); for sp in target_sp { - err.subdiagnostic(self.dcx(), errors::PatternDoesntBindName { span: sp, name }); + err.subdiagnostic(errors::PatternDoesntBindName { span: sp, name }); } for sp in origin_sp { - err.subdiagnostic(self.dcx(), errors::VariableNotInAllPatterns { span: sp }); + err.subdiagnostic(errors::VariableNotInAllPatterns { span: sp }); } if could_be_path { let import_suggestions = self.lookup_import_candidates( @@ -1446,12 +1439,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ); if macro_kind == MacroKind::Bang && ident.name == sym::macro_rules { - err.subdiagnostic(self.dcx(), MaybeMissingMacroRulesName { span: ident.span }); + err.subdiagnostic(MaybeMissingMacroRulesName { span: ident.span }); return; } if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { - err.subdiagnostic(self.dcx(), ExplicitUnsafeTraits { span: ident.span, ident }); + err.subdiagnostic(ExplicitUnsafeTraits { span: ident.span, ident }); return; } @@ -1467,14 +1460,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let scope = self.local_macro_def_scopes[&def_id]; let parent_nearest = parent_scope.module.nearest_parent_mod(); if Some(parent_nearest) == scope.opt_def_id() { - err.subdiagnostic(self.dcx(), MacroDefinedLater { span: unused_ident.span }); - err.subdiagnostic(self.dcx(), MacroSuggMovePosition { span: ident.span, ident }); + err.subdiagnostic(MacroDefinedLater { span: unused_ident.span }); + err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident }); return; } } if self.macro_names.contains(&ident.normalize_to_macros_2_0()) { - err.subdiagnostic(self.dcx(), AddedMacroUse); + err.subdiagnostic(AddedMacroUse); return; } @@ -1484,13 +1477,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let span = self.def_span(def_id); let source_map = self.tcx.sess.source_map(); let head_span = source_map.guess_head_span(span); - err.subdiagnostic( - self.dcx(), - ConsiderAddingADerive { - span: head_span.shrink_to_lo(), - suggestion: "#[derive(Default)]\n".to_string(), - }, - ); + err.subdiagnostic(ConsiderAddingADerive { + span: head_span.shrink_to_lo(), + suggestion: "#[derive(Default)]\n".to_string(), + }); } for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { if let Ok(binding) = self.early_resolve_ident_in_lexical_scope( @@ -1533,7 +1523,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { imported_ident: ident, imported_ident_desc: &desc, }; - err.subdiagnostic(self.tcx.dcx(), note); + err.subdiagnostic(note); // Silence the 'unused import' warning we might get, // since this diagnostic already covers that import. self.record_use(ident, binding, Used::Other); @@ -1544,7 +1534,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { imported_ident: ident, imported_ident_desc: &desc, }; - err.subdiagnostic(self.tcx.dcx(), note); + err.subdiagnostic(note); return; } } @@ -1599,7 +1589,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } }; did_label_def_span = true; - err.subdiagnostic(self.tcx.dcx(), label); + err.subdiagnostic(label); } let (span, msg, sugg) = if let SuggestionTarget::SimilarlyNamed = suggestion.target @@ -1790,7 +1780,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { outer_ident_descr: this_res.descr(), outer_ident, }; - err.subdiagnostic(self.tcx.dcx(), label); + err.subdiagnostic(label); } } @@ -1805,14 +1795,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { non_exhaustive = Some(attr.span); } else if let Some(span) = ctor_fields_span { let label = errors::ConstructorPrivateIfAnyFieldPrivate { span }; - err.subdiagnostic(self.tcx.dcx(), label); + err.subdiagnostic(label); if let Res::Def(_, d) = res && let Some(fields) = self.field_visibility_spans.get(&d) { let spans = fields.iter().map(|span| *span).collect(); let sugg = errors::ConsiderMakingTheFieldPublic { spans, number_of_fields: fields.len() }; - err.subdiagnostic(self.tcx.dcx(), sugg); + err.subdiagnostic(sugg); } } @@ -1921,7 +1911,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { first, dots: next_binding.is_some(), }; - err.subdiagnostic(self.tcx.dcx(), note); + err.subdiagnostic(note); } // We prioritize shorter paths, non-core imports and direct imports over the alternatives. sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport)); @@ -1940,7 +1930,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } else { errors::ImportIdent::Directly { span: dedup_span, ident, path } }; - err.subdiagnostic(self.tcx.dcx(), sugg); + err.subdiagnostic(sugg); break; } @@ -2521,14 +2511,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let note = errors::FoundItemConfigureOut { span: name.span }; - err.subdiagnostic(self.tcx.dcx(), note); + err.subdiagnostic(note); if let MetaItemKind::List(nested) = &cfg.kind && let NestedMetaItem::MetaItem(meta_item) = &nested[0] && let MetaItemKind::NameValue(feature_name) = &meta_item.kind { let note = errors::ItemWasBehindFeature { feature: feature_name.symbol }; - err.subdiagnostic(self.tcx.dcx(), note); + err.subdiagnostic(note); } } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 6c7afb305ba3..96a4647b9428 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1294,12 +1294,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // exclude decl_macro if self.get_macro_by_def_id(def_id).macro_rules => { - err.subdiagnostic(self.dcx(), ConsiderAddingMacroExport { + err.subdiagnostic( ConsiderAddingMacroExport { span: binding.span, }); } _ => { - err.subdiagnostic(self.dcx(), ConsiderMarkingAsPub { + err.subdiagnostic( ConsiderMarkingAsPub { span: import.span, ident, }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index c1e83c59f98c..5ab6ba23a7da 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -799,7 +799,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, self.r.record_partial_res(ty.id, PartialRes::new(res)); visit::walk_ty(self, ty) } - TyKind::ImplTrait(node_id, _, _) => { + TyKind::ImplTrait(node_id, _) => { let candidates = self.lifetime_elision_candidates.take(); visit::walk_ty(self, ty); self.record_lifetime_params_for_impl_trait(*node_id); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index be24755d4c5a..764cc350182a 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -829,7 +829,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { auto-traits; structs and enums can't be bound in that way", ); if bounds.iter().all(|bound| match bound { - ast::GenericBound::Outlives(_) => true, + ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..) => true, ast::GenericBound::Trait(tr, _) => tr.span == base_error.span, }) { let mut sugg = vec![]; @@ -1109,14 +1109,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { Side::Start => (segment.ident.span.between(range.span), " @ ".into()), Side::End => (range.span.to(segment.ident.span), format!("{} @ ..", segment.ident)), }; - err.subdiagnostic( - self.r.dcx(), - errors::UnexpectedResUseAtOpInSlicePatWithRangeSugg { - span, - ident: segment.ident, - snippet, - }, - ); + err.subdiagnostic(errors::UnexpectedResUseAtOpInSlicePatWithRangeSugg { + span, + ident: segment.ident, + snippet, + }); } enum Side { @@ -1208,13 +1205,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { }); if let Some(param) = param { - err.subdiagnostic( - self.r.dcx(), - errors::UnexpectedResChangeTyToConstParamSugg { - span: param.shrink_to_lo(), - applicability, - }, - ); + err.subdiagnostic(errors::UnexpectedResChangeTyToConstParamSugg { + span: param.shrink_to_lo(), + applicability, + }); } } @@ -3210,7 +3204,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { .inputs .iter() .filter_map(|param| match ¶m.ty.kind { - TyKind::ImplTrait(_, bounds, _) => Some(bounds), + TyKind::ImplTrait(_, bounds) => Some(bounds), _ => None, }) .flat_map(|bounds| bounds.into_iter()) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a622f1b577df..5f9c3a14d603 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -149,7 +149,14 @@ pub enum InstrumentCoverage { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)] pub struct CoverageOptions { pub level: CoverageLevel, - // Other boolean or enum-valued options might be added here. + + /// `-Z coverage-options=no-mir-spans`: Don't extract block coverage spans + /// from MIR statements/terminators, making it easier to inspect/debug + /// branch and MC/DC coverage mappings. + /// + /// For internal debugging only. If other code changes would make it hard + /// to keep supporting this flag, remove it. + pub no_mir_spans: bool, } /// Controls whether branch coverage or MC/DC coverage is enabled. diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index dce56382a53a..4cbc1b570225 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -3,8 +3,8 @@ use std::num::NonZero; use rustc_ast::token; use rustc_ast::util::literal::LitError; use rustc_errors::{ - codes::*, Diag, DiagCtxt, DiagMessage, Diagnostic, EmissionGuarantee, ErrorGuaranteed, Level, - MultiSpan, + codes::*, Diag, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, ErrorGuaranteed, + Level, MultiSpan, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -19,7 +19,7 @@ pub(crate) struct FeatureGateError { impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for FeatureGateError { #[track_caller] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { Diag::new(dcx, level, self.explain).with_span(self.span).with_code(E0658) } } @@ -401,7 +401,7 @@ pub fn report_lit_error( valid.then(|| format!("0{}{}", base_char.to_ascii_lowercase(), &suffix[1..])) } - let dcx = &psess.dcx; + let dcx = psess.dcx(); match err { LitError::InvalidSuffix(suffix) => { dcx.emit_err(InvalidLiteralSuffix { span, kind: lit.kind.descr(), suffix }) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index fd4a3a9e6ceb..145af50117cb 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -395,7 +395,8 @@ mod desc { pub const parse_optimization_fuel: &str = "crate=integer"; pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`"; pub const parse_instrument_coverage: &str = parse_bool; - pub const parse_coverage_options: &str = "`block` | `branch` | `condition` | `mcdc`"; + pub const parse_coverage_options: &str = + "`block` | `branch` | `condition` | `mcdc` | `no-mir-spans`"; pub const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`"; pub const parse_unpretty: &str = "`string` or `string=string`"; pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number"; @@ -963,6 +964,7 @@ mod parse { "branch" => slot.level = CoverageLevel::Branch, "condition" => slot.level = CoverageLevel::Condition, "mcdc" => slot.level = CoverageLevel::Mcdc, + "no-mir-spans" => slot.no_mir_spans = true, _ => return false, } } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index df07f81bc457..200505aaea20 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -15,8 +15,8 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc}; use rustc_errors::emitter::{stderr_destination, HumanEmitter, SilentEmitter}; use rustc_errors::{ - fallback_fluent_bundle, ColorConfig, Diag, DiagCtxt, DiagMessage, EmissionGuarantee, MultiSpan, - StashKey, + fallback_fluent_bundle, ColorConfig, Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, + EmissionGuarantee, MultiSpan, StashKey, }; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; use rustc_span::edition::Edition; @@ -106,12 +106,12 @@ pub fn feature_err_issue( // Cancel an earlier warning for this same error, if it exists. if let Some(span) = span.primary_span() { - if let Some(err) = sess.psess.dcx.steal_non_err(span, StashKey::EarlySyntaxWarning) { + if let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) { err.cancel() } } - let mut err = sess.psess.dcx.create_err(FeatureGateError { span, explain: explain.into() }); + let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() }); add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None); err } @@ -140,7 +140,7 @@ pub fn feature_warn_issue( issue: GateIssue, explain: &'static str, ) { - let mut err = sess.psess.dcx.struct_span_warn(span, explain); + let mut err = sess.dcx().struct_span_warn(span, explain); add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None); // Decorate this as a future-incompatibility lint as in rustc_middle::lint::lint_level @@ -178,30 +178,30 @@ pub fn add_feature_diagnostics_for_issue( inject_span: Option, ) { if let Some(n) = find_feature_issue(feature, issue) { - err.subdiagnostic(sess.dcx(), FeatureDiagnosticForIssue { n }); + err.subdiagnostic(FeatureDiagnosticForIssue { n }); } // #23973: do not suggest `#![feature(...)]` if we are in beta/stable if sess.psess.unstable_features.is_nightly_build() { if feature_from_cli { - err.subdiagnostic(sess.dcx(), CliFeatureDiagnosticHelp { feature }); + err.subdiagnostic(CliFeatureDiagnosticHelp { feature }); } else if let Some(span) = inject_span { - err.subdiagnostic(sess.dcx(), FeatureDiagnosticSuggestion { feature, span }); + err.subdiagnostic(FeatureDiagnosticSuggestion { feature, span }); } else { - err.subdiagnostic(sess.dcx(), FeatureDiagnosticHelp { feature }); + err.subdiagnostic(FeatureDiagnosticHelp { feature }); } if sess.opts.unstable_opts.ui_testing { - err.subdiagnostic(sess.dcx(), SuggestUpgradeCompiler::ui_testing()); + err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { - err.subdiagnostic(sess.dcx(), suggestion); + err.subdiagnostic(suggestion); } } } /// Info about a parsing session. pub struct ParseSess { - pub dcx: DiagCtxt, + dcx: DiagCtxt, pub unstable_features: UnstableFeatures, pub config: Cfg, pub check_config: CheckCfg, @@ -326,4 +326,8 @@ impl ParseSess { // AppendOnlyVec, so we resort to this scheme. self.proc_macro_quoted_spans.iter_enumerated() } + + pub fn dcx(&self) -> DiagCtxtHandle<'_> { + self.dcx.handle() + } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 87bbfcf07c84..89d029fa6e0e 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -22,8 +22,8 @@ use rustc_errors::emitter::{stderr_destination, DynEmitter, HumanEmitter, HumanR use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{ - codes::*, fallback_fluent_bundle, Diag, DiagCtxt, DiagMessage, Diagnostic, ErrorGuaranteed, - FatalAbort, FluentBundle, LazyFallbackBundle, TerminalUrl, + codes::*, fallback_fluent_bundle, Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, Diagnostic, + ErrorGuaranteed, FatalAbort, FluentBundle, LazyFallbackBundle, TerminalUrl, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -328,8 +328,8 @@ impl Session { } #[inline] - pub fn dcx(&self) -> &DiagCtxt { - &self.psess.dcx + pub fn dcx(&self) -> DiagCtxtHandle<'_> { + self.psess.dcx() } #[inline] @@ -363,6 +363,11 @@ impl Session { && self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Mcdc } + /// True if `-Zcoverage-options=no-mir-spans` was passed. + pub fn coverage_no_mir_spans(&self) -> bool { + self.opts.unstable_opts.coverage_options.no_mir_spans + } + pub fn is_sanitizer_cfi_enabled(&self) -> bool { self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI) } @@ -1065,7 +1070,7 @@ pub fn build_session( match profiler { Ok(profiler) => Some(Arc::new(profiler)), Err(e) => { - dcx.emit_warn(errors::FailedToCreateProfiler { err: e.to_string() }); + dcx.handle().emit_warn(errors::FailedToCreateProfiler { err: e.to_string() }); None } } @@ -1366,7 +1371,7 @@ impl EarlyDiagCtxt { /// format. Any errors prior to that will cause an abort and all stashed diagnostics of the /// previous dcx will be emitted. pub fn abort_if_error_and_set_error_format(&mut self, output: ErrorOutputType) { - self.dcx.abort_if_errors(); + self.dcx.handle().abort_if_errors(); let emitter = mk_emitter(output); self.dcx = DiagCtxt::new(emitter); @@ -1375,44 +1380,44 @@ impl EarlyDiagCtxt { #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_note(&self, msg: impl Into) { - self.dcx.note(msg) + self.dcx.handle().note(msg) } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_help(&self, msg: impl Into) { - self.dcx.struct_help(msg).emit() + self.dcx.handle().struct_help(msg).emit() } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] #[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"] pub fn early_err(&self, msg: impl Into) -> ErrorGuaranteed { - self.dcx.err(msg) + self.dcx.handle().err(msg) } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_fatal(&self, msg: impl Into) -> ! { - self.dcx.fatal(msg) + self.dcx.handle().fatal(msg) } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_struct_fatal(&self, msg: impl Into) -> Diag<'_, FatalAbort> { - self.dcx.struct_fatal(msg) + self.dcx.handle().struct_fatal(msg) } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_warn(&self, msg: impl Into) { - self.dcx.warn(msg) + self.dcx.handle().warn(msg) } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_struct_warn(&self, msg: impl Into) -> Diag<'_, ()> { - self.dcx.struct_warn(msg) + self.dcx.handle().struct_warn(msg) } } diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 31d2a9db01df..116056a69c1f 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -327,43 +327,24 @@ impl Span { // interner and can fall back to `Span::new`. #[inline] pub fn map_ctxt(self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) -> Span { - let (updated_ctxt32, data); match_span_kind! { self, InlineCtxt(span) => { - updated_ctxt32 = update(SyntaxContext::from_u16(span.ctxt)).as_u32(); + let updated_ctxt32 = update(SyntaxContext::from_u16(span.ctxt)).as_u32(); // Any small new context including zero will preserve the format. - if updated_ctxt32 <= MAX_CTXT { - return InlineCtxt::span(span.lo, span.len, updated_ctxt32 as u16); - } - data = span.data(); - }, - InlineParent(span) => { - updated_ctxt32 = update(SyntaxContext::root()).as_u32(); - // Only if the new context is zero the format will be preserved. - if updated_ctxt32 == 0 { - // Do nothing. - return self; - } - data = span.data(); - }, - PartiallyInterned(span) => { - updated_ctxt32 = update(SyntaxContext::from_u16(span.ctxt)).as_u32(); - // Any small new context excluding zero will preserve the format. - // Zero may change the format to `InlineParent` if parent and len are small enough. - if updated_ctxt32 <= MAX_CTXT && updated_ctxt32 != 0 { - return PartiallyInterned::span(span.index, updated_ctxt32 as u16); - } - data = span.data(); - }, - Interned(span) => { - data = span.data(); - updated_ctxt32 = update(data.ctxt).as_u32(); + return if updated_ctxt32 <= MAX_CTXT { + InlineCtxt::span(span.lo, span.len, updated_ctxt32 as u16) + } else { + span.data().with_ctxt(SyntaxContext::from_u32(updated_ctxt32)) + }; }, + InlineParent(_span) => {}, + PartiallyInterned(_span) => {}, + Interned(_span) => {}, } - // We could not keep the span in the same inline format, fall back to the complete logic. - data.with_ctxt(SyntaxContext::from_u32(updated_ctxt32)) + let data = self.data_untracked(); + data.with_ctxt(update(data.ctxt)) } // Returns either syntactic context, if it can be retrieved without taking the interner lock, diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs index b5721ee489db..9b87a1419fa3 100644 --- a/compiler/rustc_symbol_mangling/src/errors.rs +++ b/compiler/rustc_symbol_mangling/src/errors.rs @@ -1,6 +1,6 @@ //! Errors emitted by symbol_mangling. -use rustc_errors::{Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; use rustc_span::Span; use std::fmt; @@ -14,7 +14,7 @@ pub struct TestOutput { // natural language, and (b) it's only used in tests. So we construct it // manually and avoid the fluent machinery. impl Diagnostic<'_, G> for TestOutput { - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let TestOutput { span, kind, content } = self; #[allow(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index b442446f79ba..a46cba35b2d2 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,6 +1,6 @@ use crate::fluent_generated as fluent; use rustc_errors::{ - codes::*, Applicability, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, + codes::*, Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, SubdiagMessageOp, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -59,7 +59,7 @@ pub struct NegativePositiveConflict<'tcx> { impl Diagnostic<'_, G> for NegativePositiveConflict<'_> { #[track_caller] - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::trait_selection_negative_positive_conflict); diag.arg("trait_desc", self.trait_desc.print_only_trait_path().to_string()); diag.arg("self_desc", self.self_ty.map_or_else(|| "none".to_string(), |ty| ty.to_string())); diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs new file mode 100644 index 000000000000..a7c8cc5a32b6 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -0,0 +1,12 @@ +pub use rustc_next_trait_solver::solve::*; + +mod fulfill; +mod infcx; +pub mod inspect; +mod normalize; +mod select; + +pub use fulfill::{FulfillmentCtxt, NextSolverError}; +pub(crate) use normalize::deeply_normalize_for_diagnostics; +pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; +pub use select::InferCtxtSelectExt; diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 3c01d1a65f50..8937ed467a1f 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -12,13 +12,14 @@ use rustc_infer::traits::{ use rustc_middle::bug; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt}; +use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _}; use rustc_span::symbol::sym; use crate::traits::{FulfillmentError, FulfillmentErrorCode, ScrubbedTraitError}; -use super::eval_ctxt::GenerateProofTree; +use super::infcx::SolverDelegate; use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor}; -use super::{Certainty, InferCtxtEvalExt}; +use super::Certainty; /// A trait engine using the new trait solver. /// @@ -83,7 +84,9 @@ impl<'tcx> ObligationStorage<'tcx> { // change. self.overflowed.extend(self.pending.extract_if(|o| { let goal = o.clone().into(); - let result = infcx.evaluate_root_goal(goal, GenerateProofTree::No).0; + let result = <&SolverDelegate<'tcx>>::from(infcx) + .evaluate_root_goal(goal, GenerateProofTree::No) + .0; match result { Ok((has_changed, _)) => has_changed, _ => false, @@ -165,7 +168,9 @@ where let mut has_changed = false; for obligation in self.obligations.unstalled_for_select() { let goal = obligation.clone().into(); - let result = infcx.evaluate_root_goal(goal, GenerateProofTree::No).0; + let result = <&SolverDelegate<'tcx>>::from(infcx) + .evaluate_root_goal(goal, GenerateProofTree::No) + .0; self.inspect_evaluated_obligation(infcx, &obligation, &result); let (changed, certainty) = match result { Ok(result) => result, @@ -288,7 +293,10 @@ fn fulfillment_error_for_stalled<'tcx>( root_obligation: PredicateObligation<'tcx>, ) -> FulfillmentError<'tcx> { let (code, refine_obligation) = infcx.probe(|_| { - match infcx.evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::No).0 { + match <&SolverDelegate<'tcx>>::from(infcx) + .evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::No) + .0 + { Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => { (FulfillmentErrorCode::Ambiguity { overflow: None }, true) } diff --git a/compiler/rustc_trait_selection/src/solve/infcx.rs b/compiler/rustc_trait_selection/src/solve/infcx.rs new file mode 100644 index 000000000000..e574166cbfc2 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/infcx.rs @@ -0,0 +1,435 @@ +use std::ops::Deref; + +use rustc_data_structures::fx::FxHashSet; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_infer::infer::canonical::query_response::make_query_region_constraints; +use rustc_infer::infer::canonical::{ + Canonical, CanonicalExt as _, CanonicalVarInfo, CanonicalVarValues, +}; +use rustc_infer::infer::{ + BoundRegionConversionTime, InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt, +}; +use rustc_infer::traits::solve::Goal; +use rustc_infer::traits::util::supertraits; +use rustc_infer::traits::{ObligationCause, Reveal}; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _}; +use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; +use rustc_type_ir::relate::Relate; +use rustc_type_ir::solve::{Certainty, NoSolution, SolverMode}; + +use crate::traits::coherence::trait_ref_is_knowable; +use crate::traits::specialization_graph; + +#[repr(transparent)] +pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>); + +impl<'a, 'tcx> From<&'a InferCtxt<'tcx>> for &'a SolverDelegate<'tcx> { + fn from(infcx: &'a InferCtxt<'tcx>) -> Self { + // SAFETY: `repr(transparent)` + unsafe { std::mem::transmute(infcx) } + } +} + +impl<'tcx> Deref for SolverDelegate<'tcx> { + type Target = InferCtxt<'tcx>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'tcx> rustc_next_trait_solver::infcx::SolverDelegate for SolverDelegate<'tcx> { + type Interner = TyCtxt<'tcx>; + + fn interner(&self) -> TyCtxt<'tcx> { + self.0.tcx + } + + type Span = Span; + + fn solver_mode(&self) -> ty::solve::SolverMode { + match self.intercrate { + true => SolverMode::Coherence, + false => SolverMode::Normal, + } + } + + fn build_with_canonical( + interner: TyCtxt<'tcx>, + solver_mode: SolverMode, + canonical: &Canonical<'tcx, V>, + ) -> (Self, V, CanonicalVarValues<'tcx>) + where + V: TypeFoldable>, + { + let (infcx, value, vars) = interner + .infer_ctxt() + .with_next_trait_solver(true) + .intercrate(match solver_mode { + SolverMode::Normal => false, + SolverMode::Coherence => true, + }) + .build_with_canonical(DUMMY_SP, canonical); + (SolverDelegate(infcx), value, vars) + } + + fn universe(&self) -> ty::UniverseIndex { + self.0.universe() + } + + fn create_next_universe(&self) -> ty::UniverseIndex { + self.0.create_next_universe() + } + + fn universe_of_ty(&self, vid: ty::TyVid) -> Option { + // FIXME(BoxyUwU): this is kind of jank and means that printing unresolved + // ty infers will give you the universe of the var it resolved to not the universe + // it actually had. It also means that if you have a `?0.1` and infer it to `u8` then + // try to print out `?0.1` it will just print `?0`. + match self.0.probe_ty_var(vid) { + Err(universe) => Some(universe), + Ok(_) => None, + } + } + + fn universe_of_lt(&self, lt: ty::RegionVid) -> Option { + match self.0.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) { + Err(universe) => Some(universe), + Ok(_) => None, + } + } + + fn universe_of_ct(&self, ct: ty::ConstVid) -> Option { + // Same issue as with `universe_of_ty` + match self.0.probe_const_var(ct) { + Err(universe) => Some(universe), + Ok(_) => None, + } + } + + fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid { + self.0.root_var(var) + } + + fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid { + self.0.root_const_var(var) + } + + fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> Ty<'tcx> { + match self.0.probe_ty_var(vid) { + Ok(ty) => ty, + Err(_) => Ty::new_var(self.0.tcx, self.0.root_var(vid)), + } + } + + fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> { + self.0.opportunistic_resolve_int_var(vid) + } + + fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> { + self.0.opportunistic_resolve_float_var(vid) + } + + fn opportunistic_resolve_ct_var(&self, vid: ty::ConstVid) -> ty::Const<'tcx> { + match self.0.probe_const_var(vid) { + Ok(ct) => ct, + Err(_) => ty::Const::new_var(self.0.tcx, self.0.root_const_var(vid)), + } + } + + fn opportunistic_resolve_effect_var(&self, vid: ty::EffectVid) -> ty::Const<'tcx> { + match self.0.probe_effect_var(vid) { + Some(ct) => ct, + None => ty::Const::new_infer( + self.0.tcx, + ty::InferConst::EffectVar(self.0.root_effect_var(vid)), + ), + } + } + + fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { + self.0 + .inner + .borrow_mut() + .unwrap_region_constraints() + .opportunistic_resolve_var(self.0.tcx, vid) + } + + fn defining_opaque_types(&self) -> &'tcx ty::List { + self.0.defining_opaque_types() + } + + fn next_ty_infer(&self) -> Ty<'tcx> { + self.0.next_ty_var(DUMMY_SP) + } + + fn next_const_infer(&self) -> ty::Const<'tcx> { + self.0.next_const_var(DUMMY_SP) + } + + fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> { + self.0.fresh_args_for_item(DUMMY_SP, def_id) + } + + fn fresh_var_for_kind_with_span( + &self, + arg: ty::GenericArg<'tcx>, + span: Span, + ) -> ty::GenericArg<'tcx> { + match arg.unpack() { + ty::GenericArgKind::Lifetime(_) => { + self.next_region_var(RegionVariableOrigin::MiscVariable(span)).into() + } + ty::GenericArgKind::Type(_) => self.next_ty_var(span).into(), + ty::GenericArgKind::Const(_) => self.next_const_var(span).into(), + } + } + + fn instantiate_binder_with_infer> + Copy>( + &self, + value: ty::Binder<'tcx, T>, + ) -> T { + self.0.instantiate_binder_with_fresh_vars( + DUMMY_SP, + BoundRegionConversionTime::HigherRankedType, + value, + ) + } + + fn enter_forall> + Copy, U>( + &self, + value: ty::Binder<'tcx, T>, + f: impl FnOnce(T) -> U, + ) -> U { + self.0.enter_forall(value, f) + } + + fn relate>>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result>>, NoSolution> { + self.0.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs) + } + + fn eq_structurally_relating_aliases>>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result>>, NoSolution> { + self.0 + .at(&ObligationCause::dummy(), param_env) + .eq_structurally_relating_aliases_no_trace(lhs, rhs) + } + + fn resolve_vars_if_possible(&self, value: T) -> T + where + T: TypeFoldable>, + { + self.0.resolve_vars_if_possible(value) + } + + fn probe(&self, probe: impl FnOnce() -> T) -> T { + self.0.probe(|_| probe()) + } + + fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution> { + self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution) + } + + fn elaborate_supertraits( + interner: TyCtxt<'tcx>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + ) -> impl Iterator>> { + supertraits(interner, trait_ref) + } + + fn try_const_eval_resolve( + &self, + param_env: ty::ParamEnv<'tcx>, + unevaluated: ty::UnevaluatedConst<'tcx>, + ) -> Option> { + use rustc_middle::mir::interpret::ErrorHandled; + match self.const_eval_resolve(param_env, unevaluated, DUMMY_SP) { + Ok(Some(val)) => Some(ty::Const::new_value( + self.tcx, + val, + self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args), + )), + Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None, + Err(ErrorHandled::Reported(e, _)) => Some(ty::Const::new_error(self.tcx, e.into())), + } + } + + fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) { + self.0.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP), sub, sup) + } + + fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) { + self.0.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy()); + } + + fn well_formed_goals( + &self, + param_env: ty::ParamEnv<'tcx>, + arg: ty::GenericArg<'tcx>, + ) -> Option>>> { + crate::traits::wf::unnormalized_obligations(&self.0, param_env, arg).map(|obligations| { + obligations.into_iter().map(|obligation| obligation.into()).collect() + }) + } + + fn clone_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { + self.0.clone_opaque_types_for_query_response() + } + + fn make_deduplicated_outlives_constraints( + &self, + ) -> Vec>> { + // 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.0.inner.borrow().region_obligations().to_owned(); + let region_constraints = self.0.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, + ) + }); + + assert_eq!(region_constraints.member_constraints, vec![]); + + let mut seen = FxHashSet::default(); + region_constraints + .outlives + .into_iter() + .filter(|&(outlives, _)| seen.insert(outlives)) + .map(|(outlives, _)| outlives) + .collect() + } + + fn instantiate_canonical( + &self, + canonical: Canonical<'tcx, V>, + values: CanonicalVarValues<'tcx>, + ) -> V + where + V: TypeFoldable>, + { + canonical.instantiate(self.tcx, &values) + } + + fn instantiate_canonical_var_with_infer( + &self, + cv_info: CanonicalVarInfo<'tcx>, + universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, + ) -> ty::GenericArg<'tcx> { + self.0.instantiate_canonical_var(DUMMY_SP, cv_info, universe_map) + } + + fn insert_hidden_type( + &self, + opaque_type_key: ty::OpaqueTypeKey<'tcx>, + param_env: ty::ParamEnv<'tcx>, + hidden_ty: Ty<'tcx>, + goals: &mut Vec>>, + ) -> Result<(), NoSolution> { + self.0 + .insert_hidden_type(opaque_type_key, DUMMY_SP, param_env, hidden_ty, goals) + .map_err(|_| NoSolution) + } + + fn add_item_bounds_for_hidden_type( + &self, + def_id: DefId, + args: ty::GenericArgsRef<'tcx>, + param_env: ty::ParamEnv<'tcx>, + hidden_ty: Ty<'tcx>, + goals: &mut Vec>>, + ) { + self.0.add_item_bounds_for_hidden_type(def_id, args, param_env, hidden_ty, goals); + } + + fn inject_new_hidden_type_unchecked(&self, key: ty::OpaqueTypeKey<'tcx>, hidden_ty: Ty<'tcx>) { + self.0.inject_new_hidden_type_unchecked( + key, + ty::OpaqueHiddenType { ty: hidden_ty, span: DUMMY_SP }, + ) + } + + fn reset_opaque_types(&self) { + let _ = self.take_opaque_types(); + } + + fn trait_ref_is_knowable( + &self, + trait_ref: ty::TraitRef<'tcx>, + lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result, E>, + ) -> Result { + trait_ref_is_knowable(&self.0, trait_ref, lazily_normalize_ty) + .map(|is_knowable| is_knowable.is_ok()) + } + + fn fetch_eligible_assoc_item( + &self, + param_env: ty::ParamEnv<'tcx>, + goal_trait_ref: ty::TraitRef<'tcx>, + trait_assoc_def_id: DefId, + impl_def_id: DefId, + ) -> Result, NoSolution> { + let node_item = specialization_graph::assoc_def(self.tcx, impl_def_id, trait_assoc_def_id) + .map_err(|ErrorGuaranteed { .. }| NoSolution)?; + + let eligible = if node_item.is_final() { + // Non-specializable items are always projectable. + true + } else { + // Only reveal a specializable default if we're past type-checking + // and the obligation is monomorphic, otherwise passes such as + // transmute checking and polymorphic MIR optimizations could + // get a result which isn't correct for all monomorphizations. + if param_env.reveal() == Reveal::All { + let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref); + !poly_trait_ref.still_further_specializable() + } else { + trace!(?node_item.item.def_id, "not eligible due to default"); + false + } + }; + + // FIXME: Check for defaultness here may cause diagnostics problems. + if eligible { Ok(Some(node_item.item.def_id)) } else { Ok(None) } + } + + fn is_transmutable( + &self, + param_env: ty::ParamEnv<'tcx>, + dst: Ty<'tcx>, + src: Ty<'tcx>, + assume: ty::Const<'tcx>, + ) -> Result { + // Erase regions because we compute layouts in `rustc_transmute`, + // which will ICE for region vars. + let (dst, src) = self.tcx.erase_regions((dst, src)); + + let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, param_env, assume) else { + return Err(NoSolution); + }; + + // FIXME(transmutability): This really should be returning nested goals for `Answer::If*` + match rustc_transmute::TransmuteTypeEnv::new(&self.0).is_transmutable( + ObligationCause::dummy(), + rustc_transmute::Types { src, dst }, + assume, + ) { + rustc_transmute::Answer::Yes => Ok(Certainty::Yes), + rustc_transmute::Answer::No(_) | rustc_transmute::Answer::If(_) => Err(NoSolution), + } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/inspect.rs b/compiler/rustc_trait_selection/src/solve/inspect.rs new file mode 100644 index 000000000000..f100a8c2ff0e --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/inspect.rs @@ -0,0 +1,4 @@ +pub use rustc_next_trait_solver::solve::inspect::*; + +mod analyse; +pub use analyse::*; diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 464c188b6e32..cb621487125f 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -13,18 +13,16 @@ use rustc_ast_ir::try_visit; use rustc_ast_ir::visit::VisitorResult; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_macros::extension; -use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::solve::{inspect, QueryResult}; -use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause}; +use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{TyCtxt, TypeFoldable}; use rustc_middle::{bug, ty}; use rustc_next_trait_solver::resolve::EagerResolver; +use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state}; +use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _}; use rustc_span::{Span, DUMMY_SP}; -use crate::solve::eval_ctxt::canonical; -use crate::solve::{EvalCtxt, GoalEvaluationKind, GoalSource}; -use crate::solve::{GenerateProofTree, InferCtxtEvalExt}; +use crate::solve::infcx::SolverDelegate; use crate::traits::ObligationCtxt; pub struct InspectConfig { @@ -32,7 +30,7 @@ pub struct InspectConfig { } pub struct InspectGoal<'a, 'tcx> { - infcx: &'a InferCtxt<'tcx>, + infcx: &'a SolverDelegate<'tcx>, depth: usize, orig_values: Vec>, goal: Goal<'tcx, ty::Predicate<'tcx>>, @@ -162,16 +160,10 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { match **step { inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push(( source, - canonical::instantiate_canonical_state( - infcx, - span, - param_env, - &mut orig_values, - goal, - ), + instantiate_canonical_state(infcx, span, param_env, &mut orig_values, goal), )), inspect::ProbeStep::RecordImplArgs { impl_args } => { - opt_impl_args = Some(canonical::instantiate_canonical_state( + opt_impl_args = Some(instantiate_canonical_state( infcx, span, param_env, @@ -184,13 +176,8 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { } } - let () = canonical::instantiate_canonical_state( - infcx, - span, - param_env, - &mut orig_values, - self.final_state, - ); + let () = + instantiate_canonical_state(infcx, span, param_env, &mut orig_values, self.final_state); if let Some(term_hack) = self.goal.normalizes_to_term_hack { // FIXME: We ignore the expected term of `NormalizesTo` goals @@ -219,16 +206,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { // instantiating the candidate it is already constrained to the result of another // candidate. let proof_tree = infcx - .probe(|_| { - EvalCtxt::enter_root(infcx, GenerateProofTree::Yes, |ecx| { - ecx.evaluate_goal_raw( - GoalEvaluationKind::Root, - GoalSource::Misc, - goal, - ) - }) - }) - .1; + .probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes).1); InspectGoal::new( infcx, self.goal.depth + 1, @@ -388,6 +366,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { normalizes_to_term_hack: Option>, source: GoalSource, ) -> Self { + let infcx = <&SolverDelegate<'tcx>>::from(infcx); + let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, evaluation } = root; let result = evaluation.result.and_then(|ok| { if let Some(term_hack) = normalizes_to_term_hack { @@ -449,7 +429,8 @@ impl<'tcx> InferCtxt<'tcx> { depth: usize, visitor: &mut V, ) -> V::Result { - let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes); + let (_, proof_tree) = + <&SolverDelegate<'tcx>>::from(self).evaluate_root_goal(goal, GenerateProofTree::Yes); let proof_tree = proof_tree.unwrap(); visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, None, GoalSource::Misc)) } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/mod.rs b/compiler/rustc_trait_selection/src/solve/inspect/mod.rs deleted file mode 100644 index 60d52305a6be..000000000000 --- a/compiler/rustc_trait_selection/src/solve/inspect/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub use rustc_middle::traits::solve::inspect::*; - -mod build; -pub(in crate::solve) use build::*; - -mod analyse; -pub use analyse::*; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index f632f1ad4f26..038f11c60b80 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -4705,14 +4705,11 @@ fn hint_missing_borrow<'tcx>( } if !to_borrow.is_empty() { - err.subdiagnostic(infcx.dcx(), errors::AdjustSignatureBorrow::Borrow { to_borrow }); + err.subdiagnostic(errors::AdjustSignatureBorrow::Borrow { to_borrow }); } if !remove_borrow.is_empty() { - err.subdiagnostic( - infcx.dcx(), - errors::AdjustSignatureBorrow::RemoveBorrow { remove_borrow }, - ); + err.subdiagnostic(errors::AdjustSignatureBorrow::RemoveBorrow { remove_borrow }); } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b40195857712..fe047f9966f3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -19,7 +19,7 @@ use super::{ }; use crate::infer::{InferCtxt, InferOk, TypeFreshener}; -use crate::solve::InferCtxtSelectExt; +use crate::solve::InferCtxtSelectExt as _; use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::normalize::normalize_with_depth; use crate::traits::normalize::normalize_with_depth_to; diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs deleted file mode 100644 index 4a5f34e35420..000000000000 --- a/compiler/rustc_type_ir/src/infcx.rs +++ /dev/null @@ -1,77 +0,0 @@ -use crate::fold::TypeFoldable; -use crate::relate::Relate; -use crate::solve::{Goal, NoSolution}; -use crate::{self as ty, Interner}; - -pub trait InferCtxtLike: Sized { - type Interner: Interner; - - fn interner(&self) -> Self::Interner; - - fn universe_of_ty(&self, ty: ty::TyVid) -> Option; - fn universe_of_lt(&self, lt: ty::RegionVid) -> Option; - fn universe_of_ct(&self, ct: ty::ConstVid) -> Option; - - fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid; - fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid; - - fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> ::Ty; - fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> ::Ty; - fn opportunistic_resolve_float_var( - &self, - vid: ty::FloatVid, - ) -> ::Ty; - fn opportunistic_resolve_ct_var( - &self, - vid: ty::ConstVid, - ) -> ::Const; - fn opportunistic_resolve_effect_var( - &self, - vid: ty::EffectVid, - ) -> ::Const; - fn opportunistic_resolve_lt_var( - &self, - vid: ty::RegionVid, - ) -> ::Region; - - fn defining_opaque_types(&self) -> ::DefiningOpaqueTypes; - - fn next_ty_infer(&self) -> ::Ty; - fn next_const_infer(&self) -> ::Const; - fn fresh_args_for_item( - &self, - def_id: ::DefId, - ) -> ::GenericArgs; - - fn instantiate_binder_with_infer + Copy>( - &self, - value: ty::Binder, - ) -> T; - - fn enter_forall + Copy, U>( - &self, - value: ty::Binder, - f: impl FnOnce(T) -> U, - ) -> U; - - fn relate>( - &self, - param_env: ::ParamEnv, - lhs: T, - variance: ty::Variance, - rhs: T, - ) -> Result::Predicate>>, NoSolution>; - - fn eq_structurally_relating_aliases>( - &self, - param_env: ::ParamEnv, - lhs: T, - rhs: T, - ) -> Result::Predicate>>, NoSolution>; - - fn resolve_vars_if_possible(&self, value: T) -> T - where - T: TypeFoldable; - - fn probe(&self, probe: impl FnOnce() -> T) -> T; -} diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 6b84592978a2..64d3400976a8 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -8,9 +8,11 @@ use std::hash::Hash; use std::ops::Deref; use rustc_ast_ir::Mutability; +use rustc_data_structures::fx::FxHashSet; use crate::fold::{TypeFoldable, TypeSuperFoldable}; use crate::relate::Relate; +use crate::solve::{CacheData, CanonicalInput, QueryResult, Reveal}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty, CollectAndApply, Interner, UpcastFrom}; @@ -27,10 +29,14 @@ pub trait Ty>: + Relate + Flags { + fn new_unit(interner: I) -> Self; + fn new_bool(interner: I) -> Self; fn new_u8(interner: I) -> Self; + fn new_usize(interner: I) -> Self; + fn new_infer(interner: I, var: ty::InferTy) -> Self; fn new_var(interner: I, var: ty::TyVid) -> Self; @@ -107,6 +113,10 @@ pub trait Ty>: matches!(self.kind(), ty::Infer(ty::TyVar(_))) } + fn is_fn_ptr(self) -> bool { + matches!(self.kind(), ty::FnPtr(_)) + } + fn fn_sig(self, interner: I) -> ty::Binder> { match self.kind() { ty::FnPtr(sig) => sig, @@ -126,6 +136,49 @@ pub trait Ty>: _ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self), } } + + fn discriminant_ty(self, interner: I) -> I::Ty; + + fn async_destructor_ty(self, interner: I) -> I::Ty; + + /// Returns `true` when the outermost type cannot be further normalized, + /// resolved, or instantiated. This includes all primitive types, but also + /// things like ADTs and trait objects, sice even if their arguments or + /// nested types may be further simplified, the outermost [`ty::TyKind`] or + /// type constructor remains the same. + fn is_known_rigid(self) -> bool { + match self.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Pat(_, _) + | ty::Slice(_) + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Dynamic(_, _, _) + | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Tuple(_) => true, + + ty::Error(_) + | ty::Infer(_) + | ty::Alias(_, _) + | ty::Param(_) + | ty::Bound(_, _) + | ty::Placeholder(_) => false, + } + } } pub trait Tys>: @@ -200,6 +253,12 @@ pub trait Const>: fn new_expr(interner: I, expr: I::ExprConst) -> Self; + fn new_error(interner: I, guar: I::ErrorGuaranteed) -> Self; + + fn new_error_with_message(interner: I, msg: impl ToString) -> Self { + Self::new_error(interner, interner.delay_bug(msg)) + } + fn is_ct_var(self) -> bool { matches!(self.kind(), ty::ConstKind::Infer(ty::InferConst::Var(_))) } @@ -221,6 +280,37 @@ pub trait GenericArg>: + From + From { + fn as_type(&self) -> Option { + if let ty::GenericArgKind::Type(ty) = self.kind() { Some(ty) } else { None } + } + + fn expect_ty(&self) -> I::Ty { + self.as_type().expect("expected a type") + } + + fn as_const(&self) -> Option { + if let ty::GenericArgKind::Const(c) = self.kind() { Some(c) } else { None } + } + + fn expect_const(&self) -> I::Const { + self.as_const().expect("expected a const") + } + + fn as_region(&self) -> Option { + if let ty::GenericArgKind::Lifetime(c) = self.kind() { Some(c) } else { None } + } + + fn expect_region(&self) -> I::Region { + self.as_region().expect("expected a const") + } + + fn is_non_region_infer(self) -> bool { + match self.kind() { + ty::GenericArgKind::Lifetime(_) => false, + ty::GenericArgKind::Type(ty) => ty.is_ty_var(), + ty::GenericArgKind::Const(ct) => ct.is_ct_var(), + } + } } pub trait Term>: @@ -230,7 +320,7 @@ pub trait Term>: if let ty::TermKind::Ty(ty) = self.kind() { Some(ty) } else { None } } - fn expect_type(&self) -> I::Ty { + fn expect_ty(&self) -> I::Ty { self.as_type().expect("expected a type, but found a const") } @@ -248,6 +338,19 @@ pub trait Term>: ty::TermKind::Const(ct) => ct.is_ct_var(), } } + + fn to_alias_term(self) -> Option> { + match self.kind() { + ty::TermKind::Ty(ty) => match ty.kind() { + ty::Alias(_kind, alias_ty) => Some(alias_ty.into()), + _ => None, + }, + ty::TermKind::Const(ct) => match ct.kind() { + ty::ConstKind::Unevaluated(uv) => Some(uv.into()), + _ => None, + }, + } + } } pub trait GenericArgs>: @@ -260,8 +363,19 @@ pub trait GenericArgs>: + Default + Relate { + fn rebase_onto( + self, + interner: I, + source_def_id: I::DefId, + target: I::GenericArgs, + ) -> I::GenericArgs; + fn type_at(self, i: usize) -> I::Ty; + fn region_at(self, i: usize) -> I::Region; + + fn const_at(self, i: usize) -> I::Const; + fn identity_for_item(interner: I, def_id: I::DefId) -> I::GenericArgs; fn extend_with_error( @@ -301,6 +415,9 @@ pub trait Predicate>: + UpcastFrom> + UpcastFrom> + UpcastFrom>> + + UpcastFrom> + + UpcastFrom> + + UpcastFrom> + IntoKind>> { fn is_coinductive(self, interner: I) -> bool; @@ -316,9 +433,34 @@ pub trait Clause>: + Eq + TypeFoldable // FIXME: Remove these, uplift the `Upcast` impls. + + UpcastFrom> + UpcastFrom>> + + UpcastFrom> + UpcastFrom>> + + IntoKind>> { + fn as_trait_clause(self) -> Option>> { + self.kind() + .map_bound(|clause| { + if let ty::ClauseKind::Trait(t) = clause { + Some(t) + } else { + None + } + }) + .transpose() + } + fn as_projection_clause(self) -> Option>> { + self.kind() + .map_bound(|clause| { + if let ty::ClauseKind::Projection(p) = clause { + Some(p) + } else { + None + } + }) + .transpose() + } } /// Common capabilities of placeholder kinds @@ -350,16 +492,81 @@ pub trait ParamLike { pub trait AdtDef: Copy + Debug + Hash + Eq { fn def_id(self) -> I::DefId; + fn is_struct(self) -> bool; + + /// Returns the type of the struct tail. + /// + /// Expects the `AdtDef` to be a struct. If it is not, then this will panic. + fn struct_tail_ty(self, interner: I) -> Option>; + fn is_phantom_data(self) -> bool; // FIXME: perhaps use `all_fields` and expose `FieldDef`. - fn all_field_tys(self, interner: I) -> ty::EarlyBinder>; + fn all_field_tys(self, interner: I) -> ty::EarlyBinder>; fn sized_constraint(self, interner: I) -> Option>; } +pub trait ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable { + fn reveal(self) -> Reveal; + + fn caller_bounds(self) -> impl IntoIterator; +} + pub trait Features: Copy { fn generic_const_exprs(self) -> bool; fn coroutine_clone(self) -> bool; + + fn associated_const_equality(self) -> bool; +} + +pub trait EvaluationCache { + /// Insert a final result into the global cache. + fn insert( + &self, + tcx: I, + key: CanonicalInput, + proof_tree: Option, + additional_depth: usize, + encountered_overflow: bool, + cycle_participants: FxHashSet>, + dep_node: I::DepNodeIndex, + result: QueryResult, + ); + + /// Try to fetch a cached result, checking the recursion limit + /// and handling root goals of coinductive cycles. + /// + /// If this returns `Some` the cache result can be used. + fn get( + &self, + tcx: I, + key: CanonicalInput, + stack_entries: impl IntoIterator>, + available_depth: usize, + ) -> Option>; +} + +pub trait DefId: Copy + Debug + Hash + Eq + TypeFoldable { + fn as_local(self) -> Option; +} + +pub trait BoundExistentialPredicates: + Copy + + Debug + + Hash + + Eq + + Relate + + IntoIterator>> +{ + fn principal_def_id(self) -> Option; + + fn principal(self) -> Option>>; + + fn auto_traits(self) -> impl IntoIterator; + + fn projection_bounds( + self, + ) -> impl IntoIterator>>; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 11c1f73fef33..59ca95c09cd7 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -1,4 +1,5 @@ use rustc_ast_ir::Movability; +use rustc_index::bit_set::BitSet; use smallvec::SmallVec; use std::fmt::Debug; use std::hash::Hash; @@ -10,6 +11,7 @@ use crate::ir_print::IrPrint; use crate::lang_items::TraitSolverLangItem; use crate::relate::Relate; use crate::solve::inspect::CanonicalGoalEvaluationStep; +use crate::solve::{ExternalConstraintsData, PredefinedOpaquesData, SolverMode}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty}; @@ -28,9 +30,8 @@ pub trait Interner: + IrPrint> + IrPrint> { - type DefId: Copy + Debug + Hash + Eq + TypeFoldable; + type DefId: DefId; type LocalDefId: Copy + Debug + Hash + Eq + Into + TypeFoldable; - type AdtDef: AdtDef; type GenericArgs: GenericArgs; type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref; @@ -45,16 +46,53 @@ pub trait Interner: + Default; type BoundVarKind: Copy + Debug + Hash + Eq; - type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator>; - type PredefinedOpaques: Copy + Debug + Hash + Eq; - type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable; - type ExternalConstraints: Copy + Debug + Hash + Eq; + type PredefinedOpaques: Copy + + Debug + + Hash + + Eq + + TypeFoldable + + Deref>; + fn mk_predefined_opaques_in_body( + self, + data: PredefinedOpaquesData, + ) -> Self::PredefinedOpaques; + + type DefiningOpaqueTypes: Copy + + Debug + + Hash + + Default + + Eq + + TypeVisitable + + Deref>; type CanonicalGoalEvaluationStepRef: Copy + Debug + Hash + Eq + Deref>; + type CanonicalVars: Copy + + Debug + + Hash + + Eq + + IntoIterator> + + Deref]>> + + Default; + fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars; + + type ExternalConstraints: Copy + + Debug + + Hash + + Eq + + TypeFoldable + + Deref>; + fn mk_external_constraints( + self, + data: ExternalConstraintsData, + ) -> Self::ExternalConstraints; + + type DepNodeIndex; + fn with_cached_task(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex); + // Kinds of tys type Ty: Ty; type Tys: Tys; @@ -65,12 +103,7 @@ pub trait Interner: // Things stored inside of tys type ErrorGuaranteed: Copy + Debug + Hash + Eq; - type BoundExistentialPredicates: Copy - + Debug - + Hash - + Eq - + Relate - + IntoIterator>>; + type BoundExistentialPredicates: BoundExistentialPredicates; type AllocId: Copy + Debug + Hash + Eq; type Pat: Copy + Debug + Hash + Eq + Debug + Relate; type Safety: Safety; @@ -92,14 +125,15 @@ pub trait Interner: type PlaceholderRegion: PlaceholderLike; // Predicates - type ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable; + type ParamEnv: ParamEnv; type Predicate: Predicate; type Clause: Clause; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable + Flags; - fn expand_abstract_consts>(self, t: T) -> T; + type EvaluationCache: EvaluationCache; + fn evaluation_cache(self, mode: SolverMode) -> Self::EvaluationCache; - fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars; + fn expand_abstract_consts>(self, t: T) -> T; type GenericsOf: GenericsOf; fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf; @@ -111,9 +145,11 @@ pub trait Interner: + IntoIterator>; fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf; - // FIXME: Remove after uplifting `EarlyBinder` fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder; + type AdtDef: AdtDef; + fn adt_def(self, adt_def_id: Self::DefId) -> Self::AdtDef; + fn alias_ty_kind(self, alias: ty::AliasTy) -> ty::AliasTyKind; fn alias_term_kind(self, alias: ty::AliasTerm) -> ty::AliasTermKind; @@ -131,6 +167,8 @@ pub trait Interner: I: Iterator, T: CollectAndApply; + fn check_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs) -> bool; + fn check_and_mk_args( self, def_id: Self::DefId, @@ -175,6 +213,17 @@ pub trait Interner: def_id: Self::DefId, ) -> ty::EarlyBinder>; + fn predicates_of( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder>; + + fn own_predicates_of( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder>; + + // FIXME: Rename this so it's obvious it's only *immediate* super predicates. fn super_predicates_of( self, def_id: Self::DefId, @@ -184,7 +233,64 @@ pub trait Interner: fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId; + fn is_lang_item(self, def_id: Self::DefId, lang_item: TraitSolverLangItem) -> bool; + fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator; + + // FIXME: move `fast_reject` into `rustc_type_ir`. + fn args_may_unify_deep( + self, + obligation_args: Self::GenericArgs, + impl_args: Self::GenericArgs, + ) -> bool; + + fn for_each_relevant_impl( + self, + trait_def_id: Self::DefId, + self_ty: Self::Ty, + f: impl FnMut(Self::DefId), + ); + + fn has_item_definition(self, def_id: Self::DefId) -> bool; + + fn impl_is_default(self, impl_def_id: Self::DefId) -> bool; + + fn impl_trait_ref(self, impl_def_id: Self::DefId) -> ty::EarlyBinder>; + + fn impl_polarity(self, impl_def_id: Self::DefId) -> ty::ImplPolarity; + + fn trait_is_auto(self, trait_def_id: Self::DefId) -> bool; + + fn trait_is_alias(self, trait_def_id: Self::DefId) -> bool; + + fn trait_is_object_safe(self, trait_def_id: Self::DefId) -> bool; + + fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool; + + fn fn_trait_kind_from_def_id(self, trait_def_id: Self::DefId) -> Option; + + fn async_fn_trait_kind_from_def_id(self, trait_def_id: Self::DefId) -> Option; + + fn supertrait_def_ids(self, trait_def_id: Self::DefId) + -> impl IntoIterator; + + fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed; + + fn is_general_coroutine(self, coroutine_def_id: Self::DefId) -> bool; + fn coroutine_is_async(self, coroutine_def_id: Self::DefId) -> bool; + fn coroutine_is_gen(self, coroutine_def_id: Self::DefId) -> bool; + fn coroutine_is_async_gen(self, coroutine_def_id: Self::DefId) -> bool; + + fn layout_is_pointer_like(self, param_env: Self::ParamEnv, ty: Self::Ty) -> bool; + + type UnsizingParams: Deref>; + fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams; + + fn find_const_ty_from_env( + self, + param_env: Self::ParamEnv, + placeholder: Self::PlaceholderConst, + ) -> Self::Ty; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index 9a3b324fcd76..cf5ec1ab3feb 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -1,8 +1,36 @@ /// Lang items used by the new trait solver. This can be mapped to whatever internal /// representation of `LangItem`s used in the underlying compiler implementation. pub enum TraitSolverLangItem { - Future, - FutureOutput, + // tidy-alphabetical-start + AsyncDestruct, AsyncFnKindHelper, AsyncFnKindUpvars, + AsyncFnOnceOutput, + AsyncIterator, + CallOnceFuture, + CallRefFuture, + Clone, + Copy, + Coroutine, + CoroutineReturn, + CoroutineYield, + Destruct, + DiscriminantKind, + DynMetadata, + FnPtrTrait, + FusedIterator, + Future, + FutureOutput, + Iterator, + Metadata, + Option, + PointeeTrait, + PointerLike, + Poll, + Sized, + TransmuteTrait, + Tuple, + Unpin, + Unsize, + // tidy-alphabetical-end } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index ac9b2808804c..130ea231bf7e 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -45,7 +45,6 @@ mod canonical; mod const_kind; mod flags; mod generic_arg; -mod infcx; mod interner; mod opaque_ty; mod predicate; @@ -62,7 +61,6 @@ pub use codec::*; pub use const_kind::*; pub use flags::*; pub use generic_arg::*; -pub use infcx::InferCtxtLike; pub use interner::*; pub use opaque_ty::*; pub use predicate::*; diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index c0713dc50d26..bf39f9202760 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -7,7 +7,7 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen use crate::inherent::*; use crate::lift::Lift; -use crate::upcast::Upcast; +use crate::upcast::{Upcast, UpcastFrom}; use crate::visit::TypeVisitableExt as _; use crate::{self as ty, Interner}; @@ -166,6 +166,12 @@ impl ty::Binder> { } } +impl UpcastFrom> for TraitPredicate { + fn upcast_from(from: TraitRef, _tcx: I) -> Self { + TraitPredicate { trait_ref: from, polarity: PredicatePolarity::Positive } + } +} + impl fmt::Debug for TraitPredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // FIXME(effects) printing? diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs index 99d2fa744947..7934f996f0bd 100644 --- a/compiler/rustc_type_ir/src/solve.rs +++ b/compiler/rustc_type_ir/src/solve.rs @@ -57,6 +57,19 @@ pub enum Reveal { All, } +#[derive(Debug, Clone, Copy)] +pub enum SolverMode { + /// Ordinary trait solving, using everywhere except for coherence. + Normal, + /// Trait solving during coherence. There are a few notable differences + /// between coherence and ordinary trait solving. + /// + /// Most importantly, trait solving during coherence must not be incomplete, + /// i.e. return `Err(NoSolution)` for goals for which a solution exists. + /// This means that we must not make any guesses or arbitrary choices. + Coherence, +} + pub type CanonicalInput::Predicate> = Canonical>; pub type CanonicalResponse = Canonical>; /// The result of evaluating a canonical query. @@ -143,6 +156,22 @@ pub struct QueryInput { pub predefined_opaques_in_body: I::PredefinedOpaques, } +/// Opaques that are defined in the inference context before a query is called. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = ""), + Default(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct PredefinedOpaquesData { + pub opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, +} + /// Possible ways the given goal can be proven. #[derive(derivative::Derivative)] #[derivative( @@ -356,3 +385,12 @@ impl MaybeCause { } } } + +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +pub struct CacheData { + pub result: QueryResult, + pub proof_tree: Option, + pub additional_depth: usize, + pub encountered_overflow: bool, +} diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index b5a0932221ad..56ede02673c0 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -12,6 +12,8 @@ use crate::any::Any; pub use self::location::Location; #[stable(feature = "panic_hooks", since = "1.10.0")] pub use self::panic_info::PanicInfo; +#[unstable(feature = "panic_info_message", issue = "66745")] +pub use self::panic_info::PanicMessage; #[stable(feature = "catch_unwind", since = "1.9.0")] pub use self::unwind_safe::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe}; diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs index 78cf1d2e98ec..91953fd656b6 100644 --- a/library/core/src/panic/panic_info.rs +++ b/library/core/src/panic/panic_info.rs @@ -1,4 +1,4 @@ -use crate::fmt; +use crate::fmt::{self, Display}; use crate::panic::Location; /// A struct providing information about a panic. @@ -18,6 +18,17 @@ pub struct PanicInfo<'a> { force_no_backtrace: bool, } +/// A message that was given to the `panic!()` macro. +/// +/// The [`Display`] implementation of this type will format the message with the arguments +/// that were given to the `panic!()` macro. +/// +/// See [`PanicInfo::message`]. +#[unstable(feature = "panic_info_message", issue = "66745")] +pub struct PanicMessage<'a> { + message: fmt::Arguments<'a>, +} + impl<'a> PanicInfo<'a> { #[inline] pub(crate) fn new( @@ -29,12 +40,26 @@ impl<'a> PanicInfo<'a> { PanicInfo { location, message, can_unwind, force_no_backtrace } } - /// The message that was given to the `panic!` macro, - /// ready to be formatted with e.g. [`fmt::write`]. + /// The message that was given to the `panic!` macro. + /// + /// # Example + /// + /// The type returned by this method implements `Display`, so it can + /// be passed directly to [`write!()`] and similar macros. + /// + /// [`write!()`]: core::write + /// + /// ```ignore (no_std) + /// #[panic_handler] + /// fn panic_handler(panic_info: &PanicInfo<'_>) -> ! { + /// write!(DEBUG_OUTPUT, "panicked: {}", panic_info.message()); + /// loop {} + /// } + /// ``` #[must_use] #[unstable(feature = "panic_info_message", issue = "66745")] - pub fn message(&self) -> fmt::Arguments<'_> { - self.message + pub fn message(&self) -> PanicMessage<'_> { + PanicMessage { message: self.message } } /// Returns information about the location from which the panic originated, @@ -116,7 +141,7 @@ impl<'a> PanicInfo<'a> { } #[stable(feature = "panic_hook_display", since = "1.26.0")] -impl fmt::Display for PanicInfo<'_> { +impl Display for PanicInfo<'_> { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("panicked at ")?; self.location.fmt(formatter)?; @@ -125,3 +150,41 @@ impl fmt::Display for PanicInfo<'_> { Ok(()) } } + +impl<'a> PanicMessage<'a> { + /// Get the formatted message, if it has no arguments to be formatted at runtime. + /// + /// This can be used to avoid allocations in some cases. + /// + /// # Guarantees + /// + /// For `panic!("just a literal")`, this function is guaranteed to + /// return `Some("just a literal")`. + /// + /// For most cases with placeholders, this function will return `None`. + /// + /// See [`fmt::Arguments::as_str`] for details. + #[unstable(feature = "panic_info_message", issue = "66745")] + #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")] + #[must_use] + #[inline] + pub const fn as_str(&self) -> Option<&'static str> { + self.message.as_str() + } +} + +#[unstable(feature = "panic_info_message", issue = "66745")] +impl Display for PanicMessage<'_> { + #[inline] + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_fmt(self.message) + } +} + +#[unstable(feature = "panic_info_message", issue = "66745")] +impl fmt::Debug for PanicMessage<'_> { + #[inline] + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_fmt(self.message) + } +} diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 2bb5ea28b181..ebd054156951 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -593,19 +593,18 @@ pub fn panicking() -> bool { #[panic_handler] pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { struct FormatStringPayload<'a> { - inner: &'a fmt::Arguments<'a>, + inner: &'a core::panic::PanicMessage<'a>, string: Option, } impl FormatStringPayload<'_> { fn fill(&mut self) -> &mut String { - use crate::fmt::Write; - let inner = self.inner; // Lazily, the first time this gets called, run the actual string formatting. self.string.get_or_insert_with(|| { let mut s = String::new(); - let _err = s.write_fmt(*inner); + let mut fmt = fmt::Formatter::new(&mut s); + let _err = fmt::Display::fmt(&inner, &mut fmt); s }) } @@ -627,7 +626,11 @@ pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { impl fmt::Display for FormatStringPayload<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(s) = &self.string { f.write_str(s) } else { f.write_fmt(*self.inner) } + if let Some(s) = &self.string { + f.write_str(s) + } else { + fmt::Display::fmt(&self.inner, f) + } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2dcbbf0d1509..da41f974068e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -228,6 +228,8 @@ fn clean_generic_bound<'tcx>( GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier) } + // FIXME(precise_capturing): Implement rustdoc support + hir::GenericBound::Use(..) => return None, }) } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 78d4129f6422..45bd1616e83c 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -8,6 +8,7 @@ use std::path::PathBuf; use std::str::FromStr; use rustc_data_structures::fx::FxHashMap; +use rustc_errors::DiagCtxtHandle; use rustc_session::config::{ self, parse_crate_types_from_list, parse_externs, parse_target_triple, CrateType, }; @@ -383,9 +384,10 @@ impl Options { }; let dcx = new_dcx(error_format, None, diagnostic_width, &unstable_opts); + let dcx = dcx.handle(); // check for deprecated options - check_deprecated_options(matches, &dcx); + check_deprecated_options(matches, dcx); if matches.opt_strs("passes") == ["list"] { println!("Available passes for running rustdoc:"); @@ -458,7 +460,7 @@ impl Options { println!("rustdoc: [check-theme] Starting tests! (Ignoring all other arguments)"); for theme_file in to_check.iter() { print!(" - Checking \"{theme_file}\"..."); - let (success, differences) = theme::test_theme_against(theme_file, &paths, &dcx); + let (success, differences) = theme::test_theme_against(theme_file, &paths, dcx); if !differences.is_empty() || !success { println!(" FAILED"); errors += 1; @@ -603,7 +605,7 @@ impl Options { .with_help("arguments to --theme must have a .css extension") .emit(); } - let (success, ret) = theme::test_theme_against(&theme_file, &paths, &dcx); + let (success, ret) = theme::test_theme_against(&theme_file, &paths, dcx); if !success { dcx.fatal(format!("error loading theme file: \"{theme_s}\"")); } else if !ret.is_empty() { @@ -630,7 +632,7 @@ impl Options { &matches.opt_strs("markdown-before-content"), &matches.opt_strs("markdown-after-content"), nightly_options::match_is_nightly_build(matches), - &dcx, + dcx, &mut id_map, edition, &None, @@ -741,9 +743,9 @@ impl Options { ); } - let scrape_examples_options = ScrapeExamplesOptions::new(matches, &dcx); + let scrape_examples_options = ScrapeExamplesOptions::new(matches, dcx); let with_examples = matches.opt_strs("with-examples"); - let call_locations = crate::scrape_examples::load_call_locations(with_examples, &dcx); + let call_locations = crate::scrape_examples::load_call_locations(with_examples, dcx); let unstable_features = rustc_feature::UnstableFeatures::from_environment(crate_name.as_deref()); @@ -847,7 +849,7 @@ fn parse_remap_path_prefix( } /// Prints deprecation warnings for deprecated options -fn check_deprecated_options(matches: &getopts::Matches, dcx: &rustc_errors::DiagCtxt) { +fn check_deprecated_options(matches: &getopts::Matches, dcx: DiagCtxtHandle<'_>) { let deprecated_flags = []; for &flag in deprecated_flags.iter() { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index ce098a1bcfbf..5d8e61f9fa0d 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -3,7 +3,7 @@ use rustc_data_structures::sync::Lrc; use rustc_data_structures::unord::UnordSet; use rustc_errors::emitter::{stderr_destination, DynEmitter, HumanEmitter}; use rustc_errors::json::JsonEmitter; -use rustc_errors::{codes::*, ErrorGuaranteed, TerminalUrl}; +use rustc_errors::{codes::*, DiagCtxtHandle, ErrorGuaranteed, TerminalUrl}; use rustc_feature::UnstableFeatures; use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId}; @@ -379,7 +379,7 @@ pub(crate) fn run_global_ctxt( ); } - fn report_deprecated_attr(name: &str, dcx: &rustc_errors::DiagCtxt, sp: Span) { + fn report_deprecated_attr(name: &str, dcx: DiagCtxtHandle<'_>, sp: Span) { let mut msg = dcx.struct_span_warn(sp, format!("the `#![doc({name})]` attribute is deprecated")); msg.note( diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 81a7463decad..40cc4a9d4412 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -7,7 +7,7 @@ pub(crate) use markdown::test as test_markdown; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{ColorConfig, ErrorGuaranteed, FatalError}; +use rustc_errors::{ColorConfig, DiagCtxtHandle, ErrorGuaranteed, FatalError}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::CRATE_HIR_ID; use rustc_interface::interface; @@ -90,10 +90,7 @@ fn get_doctest_dir() -> io::Result { TempFileBuilder::new().prefix("rustdoctest").tempdir() } -pub(crate) fn run( - dcx: &rustc_errors::DiagCtxt, - options: RustdocOptions, -) -> Result<(), ErrorGuaranteed> { +pub(crate) fn run(dcx: DiagCtxtHandle<'_>, options: RustdocOptions) -> Result<(), ErrorGuaranteed> { let invalid_codeblock_attributes_name = crate::lint::INVALID_CODEBLOCK_ATTRIBUTES.name; // See core::create_config for what's going on here. diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 599611407ed8..74833c113623 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -229,7 +229,7 @@ fn check_for_main_and_extern_crate( // dcx. Any errors in the tests will be reported when the test file is compiled, // Note that we still need to cancel the errors above otherwise `Diag` will panic on // drop. - psess.dcx.reset_err_count(); + psess.dcx().reset_err_count(); (found_main, found_extern_crate, found_macro) }) diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 03ee042aa8d0..62cdc0bd5a60 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -1,4 +1,5 @@ use crate::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground}; +use rustc_errors::DiagCtxtHandle; use rustc_span::edition::Edition; use std::fs; use std::path::Path; @@ -27,7 +28,7 @@ impl ExternalHtml { md_before_content: &[String], md_after_content: &[String], nightly_build: bool, - dcx: &rustc_errors::DiagCtxt, + dcx: DiagCtxtHandle<'_>, id_map: &mut IdMap, edition: Edition, playground: &Option, @@ -75,7 +76,7 @@ pub(crate) enum LoadStringError { pub(crate) fn load_string>( file_path: P, - dcx: &rustc_errors::DiagCtxt, + dcx: DiagCtxtHandle<'_>, ) -> Result { let file_path = file_path.as_ref(); let contents = match fs::read(file_path) { @@ -98,7 +99,7 @@ pub(crate) fn load_string>( } } -fn load_external_files(names: &[String], dcx: &rustc_errors::DiagCtxt) -> Option { +fn load_external_files(names: &[String], dcx: DiagCtxtHandle<'_>) -> Option { let mut out = String::new(); for name in names { let Ok(s) = load_string(name, dcx) else { return None }; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index d6e715d48ea5..fb4cd218b84c 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -77,7 +77,7 @@ use std::io::{self, IsTerminal}; use std::process; use std::sync::{atomic::AtomicBool, Arc}; -use rustc_errors::{ErrorGuaranteed, FatalError}; +use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError}; use rustc_interface::interface; use rustc_middle::ty::TyCtxt; use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup}; @@ -670,7 +670,7 @@ fn usage(argv0: &str) { /// A result type used by several functions under `main()`. type MainResult = Result<(), ErrorGuaranteed>; -pub(crate) fn wrap_return(dcx: &rustc_errors::DiagCtxt, res: Result<(), String>) -> MainResult { +pub(crate) fn wrap_return(dcx: DiagCtxtHandle<'_>, res: Result<(), String>) -> MainResult { match res { Ok(()) => dcx.has_errors().map_or(Ok(()), Err), Err(err) => Err(dcx.err(err)), @@ -732,12 +732,13 @@ fn main_args( None => return Ok(()), }; - let diag = + let dcx = core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts); + let dcx = dcx.handle(); match (options.should_test, options.markdown_input()) { - (true, Some(_)) => return wrap_return(&diag, doctest::test_markdown(options)), - (true, None) => return doctest::run(&diag, options), + (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(options)), + (true, None) => return doctest::run(dcx, options), (false, Some(input)) => { let input = input.to_owned(); let edition = options.edition; @@ -747,7 +748,7 @@ fn main_args( // requires session globals and a thread pool, so we use // `run_compiler`. return wrap_return( - &diag, + dcx, interface::run_compiler(config, |_compiler| { markdown::render(&input, render_options, edition) }), diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index e9b380fdeac6..5a595e039535 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -7,6 +7,7 @@ use crate::formats::renderer::FormatRenderer; use crate::html::render::Context; use rustc_data_structures::fx::FxHashMap; +use rustc_errors::DiagCtxtHandle; use rustc_hir::{ self as hir, intravisit::{self, Visitor}, @@ -38,7 +39,7 @@ pub(crate) struct ScrapeExamplesOptions { } impl ScrapeExamplesOptions { - pub(crate) fn new(matches: &getopts::Matches, dcx: &rustc_errors::DiagCtxt) -> Option { + pub(crate) fn new(matches: &getopts::Matches, dcx: DiagCtxtHandle<'_>) -> Option { let output_path = matches.opt_str("scrape-examples-output-path"); let target_crates = matches.opt_strs("scrape-examples-target-crate"); let scrape_tests = matches.opt_present("scrape-tests"); @@ -336,7 +337,7 @@ pub(crate) fn run( // options. pub(crate) fn load_call_locations( with_examples: Vec, - dcx: &rustc_errors::DiagCtxt, + dcx: DiagCtxtHandle<'_>, ) -> AllCallLocations { let mut all_calls: AllCallLocations = FxHashMap::default(); for path in with_examples { diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs index 31d32e23f8eb..2fa54a9cd812 100644 --- a/src/librustdoc/theme.rs +++ b/src/librustdoc/theme.rs @@ -5,7 +5,7 @@ use std::iter::Peekable; use std::path::Path; use std::str::Chars; -use rustc_errors::DiagCtxt; +use rustc_errors::DiagCtxtHandle; #[cfg(test)] mod tests; @@ -236,7 +236,7 @@ pub(crate) fn get_differences( pub(crate) fn test_theme_against>( f: &P, origin: &FxHashMap, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, ) -> (bool, Vec) { let against = match fs::read_to_string(f) .map_err(|e| e.to_string()) diff --git a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs index 06ae1723a03d..4922c87b206c 100644 --- a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs +++ b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs @@ -73,7 +73,7 @@ fn type_param_bounds<'tcx>(generics: &'tcx Generics<'tcx>) -> impl Iterator None, + GenericBound::Outlives(_) | GenericBound::Use(..) => None, }) .filter(|bound| !bound.trait_bound.span.from_expansion()), ) diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index c70f5c2df842..fb43f7d80aff 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -724,11 +724,8 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool { (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)), (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound), - (ImplTrait(_, lg, lc), ImplTrait(_, rg, rc)) => { + (ImplTrait(_, lg), ImplTrait(_, rg)) => { over(lg, rg, eq_generic_bound) - && both(lc, rc, |lc, rc| { - over(lc.0.as_slice(), rc.0.as_slice(), eq_precise_capture) - }) }, (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index f79da26964f3..6117e76897f2 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -180,12 +180,12 @@ pub fn main() { rustc_driver::init_rustc_env_logger(&early_dcx); - let using_internal_features = rustc_driver::install_ice_hook(BUG_REPORT_URL, |handler| { + let using_internal_features = rustc_driver::install_ice_hook(BUG_REPORT_URL, |dcx| { // FIXME: this macro calls unwrap internally but is called in a panicking context! It's not // as simple as moving the call from the hook to main, because `install_ice_hook` doesn't // accept a generic closure. let version_info = rustc_tools_util::get_version_info!(); - handler.note(format!("Clippy version: {version_info}")); + dcx.handle().note(format!("Clippy version: {version_info}")); }); exit(rustc_driver::catch_with_exit_code(move || { diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 47f0913accee..139c81a9d40c 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -569,7 +569,7 @@ pub fn report_msg<'tcx>( let is_local = machine.is_local(frame_info); // No span for non-local frames and the first frame (which is the error site). if is_local && idx > 0 { - err.subdiagnostic(err.dcx, frame_info.as_note(machine.tcx)); + err.subdiagnostic(frame_info.as_note(machine.tcx)); } else { let sm = sess.source_map(); let span = sm.span_to_embeddable_string(frame_info.span); diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index a358ae83de1b..f4c101cf81c4 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -30,7 +30,8 @@ pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc}; pub use clang::{clang, Clang}; pub use diff::{diff, Diff}; pub use llvm::{ - llvm_filecheck, llvm_profdata, llvm_readobj, LlvmFilecheck, LlvmProfdata, LlvmReadobj, + llvm_filecheck, llvm_objdump, llvm_profdata, llvm_readobj, LlvmFilecheck, LlvmObjdump, + LlvmProfdata, LlvmReadobj, }; pub use run::{cmd, run, run_fail, run_with_args}; pub use rustc::{aux_build, rustc, Rustc}; @@ -303,6 +304,34 @@ pub fn set_host_rpath(cmd: &mut Command) { }); } +/// Read the contents of a file that cannot simply be read by +/// read_to_string, due to invalid utf8 data, then assert that it contains `expected`. +#[track_caller] +pub fn invalid_utf8_contains>(path: P, expected: &str) { + let buffer = fs_wrapper::read(path.as_ref()); + if !String::from_utf8_lossy(&buffer).contains(expected) { + eprintln!("=== FILE CONTENTS (LOSSY) ==="); + eprintln!("{}", String::from_utf8_lossy(&buffer)); + eprintln!("=== SPECIFIED TEXT ==="); + eprintln!("{}", expected); + panic!("specified text was not found in file"); + } +} + +/// Read the contents of a file that cannot simply be read by +/// read_to_string, due to invalid utf8 data, then assert that it does not contain `expected`. +#[track_caller] +pub fn invalid_utf8_not_contains>(path: P, expected: &str) { + let buffer = fs_wrapper::read(path.as_ref()); + if String::from_utf8_lossy(&buffer).contains(expected) { + eprintln!("=== FILE CONTENTS (LOSSY) ==="); + eprintln!("{}", String::from_utf8_lossy(&buffer)); + eprintln!("=== SPECIFIED TEXT ==="); + eprintln!("{}", expected); + panic!("specified text was unexpectedly found in file"); + } +} + /// Copy a directory into another. pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) { fn copy_dir_all_inner(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { diff --git a/src/tools/run-make-support/src/llvm.rs b/src/tools/run-make-support/src/llvm.rs index 664093e072d7..fe4131819bae 100644 --- a/src/tools/run-make-support/src/llvm.rs +++ b/src/tools/run-make-support/src/llvm.rs @@ -23,6 +23,12 @@ pub fn llvm_filecheck() -> LlvmFilecheck { LlvmFilecheck::new() } +/// Construct a new `llvm-objdump` invocation. This assumes that `llvm-objdump` is available +/// at `$LLVM_BIN_DIR/llvm-objdump`. +pub fn llvm_objdump() -> LlvmObjdump { + LlvmObjdump::new() +} + /// A `llvm-readobj` invocation builder. #[derive(Debug)] #[must_use] @@ -44,9 +50,17 @@ pub struct LlvmFilecheck { cmd: Command, } +/// A `llvm-objdump` invocation builder. +#[derive(Debug)] +#[must_use] +pub struct LlvmObjdump { + cmd: Command, +} + crate::impl_common_helpers!(LlvmReadobj); crate::impl_common_helpers!(LlvmProfdata); crate::impl_common_helpers!(LlvmFilecheck); +crate::impl_common_helpers!(LlvmObjdump); /// Generate the path to the bin directory of LLVM. #[must_use] @@ -131,3 +145,19 @@ impl LlvmFilecheck { self } } + +impl LlvmObjdump { + /// Construct a new `llvm-objdump` invocation. This assumes that `llvm-objdump` is available + /// at `$LLVM_BIN_DIR/llvm-objdump`. + pub fn new() -> Self { + let llvm_objdump = llvm_bin_dir().join("llvm-objdump"); + let cmd = Command::new(llvm_objdump); + Self { cmd } + } + + /// Provide an input file. + pub fn input>(&mut self, path: P) -> &mut Self { + self.cmd.arg(path.as_ref()); + self + } +} diff --git a/src/tools/rustfmt/src/parse/macros/cfg_if.rs b/src/tools/rustfmt/src/parse/macros/cfg_if.rs index 5fc988e43193..b91d203d5311 100644 --- a/src/tools/rustfmt/src/parse/macros/cfg_if.rs +++ b/src/tools/rustfmt/src/parse/macros/cfg_if.rs @@ -67,7 +67,7 @@ fn parse_cfg_if_inner<'a>( Ok(None) => continue, Err(err) => { err.cancel(); - parser.psess.dcx.reset_err_count(); + parser.psess.dcx().reset_err_count(); return Err( "Expected item inside cfg_if block, but failed to parse it as an item", ); diff --git a/src/tools/rustfmt/src/parse/macros/lazy_static.rs b/src/tools/rustfmt/src/parse/macros/lazy_static.rs index badd95699500..7026935294ac 100644 --- a/src/tools/rustfmt/src/parse/macros/lazy_static.rs +++ b/src/tools/rustfmt/src/parse/macros/lazy_static.rs @@ -16,8 +16,8 @@ pub(crate) fn parse_lazy_static( ($method:ident $(,)* $($arg:expr),* $(,)*) => { match parser.$method($($arg,)*) { Ok(val) => { - if parser.psess.dcx.has_errors().is_some() { - parser.psess.dcx.reset_err_count(); + if parser.psess.dcx().has_errors().is_some() { + parser.psess.dcx().reset_err_count(); return None; } else { val @@ -25,7 +25,7 @@ pub(crate) fn parse_lazy_static( } Err(err) => { err.cancel(); - parser.psess.dcx.reset_err_count(); + parser.psess.dcx().reset_err_count(); return None; } } diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs index cbcc0b2d6364..89169e10715b 100644 --- a/src/tools/rustfmt/src/parse/macros/mod.rs +++ b/src/tools/rustfmt/src/parse/macros/mod.rs @@ -29,8 +29,8 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option { if Parser::nonterminal_may_begin_with($nt_kind, &cloned_parser.token) { match $try_parse(&mut cloned_parser) { Ok(x) => { - if parser.psess.dcx.has_errors().is_some() { - parser.psess.dcx.reset_err_count(); + if parser.psess.dcx().has_errors().is_some() { + parser.psess.dcx().reset_err_count(); } else { // Parsing succeeded. *parser = cloned_parser; @@ -39,7 +39,7 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option { } Err(e) => { e.cancel(); - parser.psess.dcx.reset_err_count(); + parser.psess.dcx().reset_err_count(); } } } diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index 1a39d212386b..f4fbabaf6c91 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -210,7 +210,9 @@ impl ParseSess { rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false, ); - self.raw_psess.dcx.make_silent(fallback_bundle, None, false); + self.raw_psess + .dcx() + .make_silent(fallback_bundle, None, false); } pub(crate) fn span_to_filename(&self, span: Span) -> FileName { @@ -286,11 +288,11 @@ impl ParseSess { } pub(super) fn has_errors(&self) -> bool { - self.raw_psess.dcx.has_errors().is_some() + self.raw_psess.dcx().has_errors().is_some() } pub(super) fn reset_errors(&self) { - self.raw_psess.dcx.reset_err_count(); + self.raw_psess.dcx().reset_err_count(); } } diff --git a/src/tools/rustfmt/src/spanned.rs b/src/tools/rustfmt/src/spanned.rs index 4aaf7fdb27fb..28911f8af1df 100644 --- a/src/tools/rustfmt/src/spanned.rs +++ b/src/tools/rustfmt/src/spanned.rs @@ -181,6 +181,7 @@ impl Spanned for ast::GenericBound { match *self { ast::GenericBound::Trait(ref ptr, _) => ptr.span, ast::GenericBound::Outlives(ref l) => l.ident.span, + ast::GenericBound::Use(_, span) => span, } } } diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 7d14d9e727ab..c2c192738c91 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -563,6 +563,8 @@ impl Rewrite for ast::GenericBound { .map(|s| if has_paren { format!("({})", s) } else { s }) } ast::GenericBound::Outlives(ref lifetime) => lifetime.rewrite(context, shape), + // FIXME(precise_capturing): Should implement formatting before stabilization. + ast::GenericBound::Use(..) => None, } } } @@ -843,11 +845,7 @@ impl Rewrite for ast::Ty { rewrite_macro(mac, None, context, shape, MacroPosition::Expression) } ast::TyKind::ImplicitSelf => Some(String::from("")), - ast::TyKind::ImplTrait(_, ref it, ref captures) => { - // FIXME(precise_capturing): Implement formatting. - if captures.is_some() { - return None; - } + ast::TyKind::ImplTrait(_, ref it) => { // Empty trait is not a parser error. if it.is_empty() { return Some("impl".to_owned()); @@ -932,6 +930,8 @@ fn is_generic_bounds_in_order(generic_bounds: &[ast::GenericBound]) -> bool { let is_trait = |b: &ast::GenericBound| match b { ast::GenericBound::Outlives(..) => false, ast::GenericBound::Trait(..) => true, + // FIXME(precise_capturing): This ordering fn should be reworked. + ast::GenericBound::Use(..) => false, }; let is_lifetime = |b: &ast::GenericBound| !is_trait(b); let last_trait_index = generic_bounds.iter().rposition(is_trait); @@ -966,6 +966,8 @@ fn join_bounds_inner( let is_bound_extendable = |s: &str, b: &ast::GenericBound| match b { ast::GenericBound::Outlives(..) => true, ast::GenericBound::Trait(..) => last_line_extendable(s), + // FIXME(precise_capturing): This ordering fn should be reworked. + ast::GenericBound::Use(..) => true, }; // Whether a GenericBound item is a PathSegment segment that includes internal array @@ -1110,8 +1112,7 @@ fn join_bounds_inner( pub(crate) fn opaque_ty(ty: &Option>) -> Option<&ast::GenericBounds> { ty.as_ref().and_then(|t| match &t.kind { - // FIXME(precise_capturing): Implement support here - ast::TyKind::ImplTrait(_, bounds, _) => Some(bounds), + ast::TyKind::ImplTrait(_, bounds) => Some(bounds), _ => None, }) } diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 895798d7c1f9..12d5f3576ca8 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,4 +1,3 @@ -run-make/allocator-shim-circular-deps/Makefile run-make/archive-duplicate-names/Makefile run-make/atomic-lock-free/Makefile run-make/branch-protection-check-IBT/Makefile @@ -35,12 +34,10 @@ run-make/emit-shared-files/Makefile run-make/emit-stack-sizes/Makefile run-make/emit-to-stdout/Makefile run-make/env-dep-info/Makefile -run-make/error-found-staticlib-instead-crate/Makefile run-make/error-writing-dependencies/Makefile run-make/export-executable-symbols/Makefile run-make/extern-diff-internal-name/Makefile run-make/extern-flag-disambiguates/Makefile -run-make/extern-flag-fun/Makefile run-make/extern-flag-pathless/Makefile run-make/extern-flag-rename-transitive/Makefile run-make/extern-fn-explicit-align/Makefile @@ -64,14 +61,11 @@ run-make/glibc-staticlib-args/Makefile run-make/include_bytes_deps/Makefile run-make/incr-add-rust-src-component/Makefile run-make/incr-foreign-head-span/Makefile -run-make/incremental-debugger-visualizer/Makefile -run-make/incremental-session-fail/Makefile run-make/inline-always-many-cgu/Makefile run-make/interdependent-c-libraries/Makefile run-make/intrinsic-unreachable/Makefile run-make/invalid-library/Makefile run-make/invalid-so/Makefile -run-make/invalid-staticlib/Makefile run-make/issue-107094/Makefile run-make/issue-109934-lto-debuginfo/Makefile run-make/issue-14698/Makefile @@ -90,7 +84,6 @@ run-make/issue-40535/Makefile run-make/issue-47384/Makefile run-make/issue-47551/Makefile run-make/issue-51671/Makefile -run-make/issue-64153/Makefile run-make/issue-68794-textrel-on-minimal-lib/Makefile run-make/issue-69368/Makefile run-make/issue-83045/Makefile @@ -135,18 +128,13 @@ run-make/missing-crate-dependency/Makefile run-make/mixing-libs/Makefile run-make/msvc-opt-minsize/Makefile run-make/native-link-modifier-bundle/Makefile -run-make/native-link-modifier-verbatim-linker/Makefile -run-make/native-link-modifier-verbatim-rustc/Makefile run-make/native-link-modifier-whole-archive/Makefile run-make/no-alloc-shim/Makefile run-make/no-builtins-attribute/Makefile -run-make/no-builtins-lto/Makefile run-make/no-duplicate-libs/Makefile run-make/obey-crate-type-flag/Makefile run-make/optimization-remarks-dir-pgo/Makefile run-make/optimization-remarks-dir/Makefile -run-make/output-filename-conflicts-with-directory/Makefile -run-make/output-filename-overwrites-input/Makefile run-make/output-type-permutations/Makefile run-make/override-aliased-flags/Makefile run-make/overwrite-input/Makefile @@ -196,8 +184,6 @@ run-make/rustdoc-io-error/Makefile run-make/sanitizer-cdylib-link/Makefile run-make/sanitizer-dylib-link/Makefile run-make/sanitizer-staticlib-link/Makefile -run-make/separate-link-fail/Makefile -run-make/separate-link/Makefile run-make/sepcomp-cci-copies/Makefile run-make/sepcomp-inlining/Makefile run-make/sepcomp-separate/Makefile @@ -231,7 +217,6 @@ run-make/unknown-mod-stdin/Makefile run-make/unstable-flag-required/Makefile run-make/use-suggestions-rust-2018/Makefile run-make/used-cdylib-macos/Makefile -run-make/used/Makefile run-make/volatile-intrinsics/Makefile run-make/wasm-exceptions-nostd/Makefile run-make/wasm-override-linker/Makefile diff --git a/tests/coverage/attr/nested.cov-map b/tests/coverage/attr/nested.cov-map new file mode 100644 index 000000000000..a613bb7f8cdf --- /dev/null +++ b/tests/coverage/attr/nested.cov-map @@ -0,0 +1,100 @@ +Function name: <<::trait_method::MyMiddle as nested::MyTrait>::trait_method::MyInner as nested::MyTrait>::trait_method (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 39, 15, 02, 16] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 57, 21) to (start + 2, 22) + +Function name: <<::outer_method::MyMiddle>::middle_method::MyInner>::inner_method (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 23, 15, 02, 16] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 35, 21) to (start + 2, 22) + +Function name: <::trait_method::MyMiddle as nested::MyTrait>::trait_method (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 36, 0d, 08, 0e] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 54, 13) to (start + 8, 14) + +Function name: <::outer_method::MyMiddle>::middle_method (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 20, 0d, 08, 0e] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 32, 13) to (start + 8, 14) + +Function name: nested::closure_expr +Raw bytes (14): 0x[01, 01, 00, 02, 01, 44, 01, 01, 0f, 01, 0b, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 68, 1) to (start + 1, 15) +- Code(Counter(0)) at (prev + 11, 5) to (start + 1, 2) + +Function name: nested::closure_expr::{closure#0}::{closure#0} (unused) +Raw bytes (14): 0x[01, 01, 00, 02, 00, 47, 1a, 01, 17, 00, 04, 0d, 01, 0a] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 71, 26) to (start + 1, 23) +- Code(Zero) at (prev + 4, 13) to (start + 1, 10) + +Function name: nested::closure_expr::{closure#0}::{closure#0}::{closure#0} (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 48, 1d, 02, 0e] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 72, 29) to (start + 2, 14) + +Function name: nested::closure_tail +Raw bytes (14): 0x[01, 01, 00, 02, 01, 53, 01, 01, 0f, 01, 11, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 83, 1) to (start + 1, 15) +- Code(Counter(0)) at (prev + 17, 5) to (start + 1, 2) + +Function name: nested::closure_tail::{closure#0}::{closure#0} (unused) +Raw bytes (14): 0x[01, 01, 00, 02, 00, 58, 14, 01, 1f, 00, 06, 15, 01, 12] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 88, 20) to (start + 1, 31) +- Code(Zero) at (prev + 6, 21) to (start + 1, 18) + +Function name: nested::closure_tail::{closure#0}::{closure#0}::{closure#0} (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 5a, 1c, 02, 1a] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 90, 28) to (start + 2, 26) + +Function name: nested::outer_fn::middle_fn (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 05, 05, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 17, 5) to (start + 5, 6) + +Function name: nested::outer_fn::middle_fn::inner_fn (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 12, 09, 02, 0a] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 18, 9) to (start + 2, 10) + diff --git a/tests/coverage/attr/nested.coverage b/tests/coverage/attr/nested.coverage new file mode 100644 index 000000000000..13129572aec7 --- /dev/null +++ b/tests/coverage/attr/nested.coverage @@ -0,0 +1,111 @@ + LL| |#![feature(coverage_attribute, stmt_expr_attributes)] + LL| |//@ edition: 2021 + LL| | + LL| |// Demonstrates the interaction between #[coverage(off)] and various kinds of + LL| |// nested function. + LL| | + LL| |// FIXME(#126625): Coverage attributes should apply recursively to nested functions. + LL| |// FIXME(#126626): When an inner (non-closure) function has `#[coverage(off)]`, + LL| |// its lines can still be marked with misleading execution counts from its enclosing + LL| |// function. + LL| | + LL| |#[coverage(off)] + LL| |fn do_stuff() {} + LL| | + LL| |#[coverage(off)] + LL| |fn outer_fn() { + LL| 0| fn middle_fn() { + LL| 0| fn inner_fn() { + LL| 0| do_stuff(); + LL| 0| } + LL| 0| do_stuff(); + LL| 0| } + LL| | do_stuff(); + LL| |} + LL| | + LL| |struct MyOuter; + LL| |impl MyOuter { + LL| | #[coverage(off)] + LL| | fn outer_method(&self) { + LL| | struct MyMiddle; + LL| | impl MyMiddle { + LL| 0| fn middle_method(&self) { + LL| 0| struct MyInner; + LL| 0| impl MyInner { + LL| 0| fn inner_method(&self) { + LL| 0| do_stuff(); + LL| 0| } + LL| 0| } + LL| 0| do_stuff(); + LL| 0| } + LL| | } + LL| | do_stuff(); + LL| | } + LL| |} + LL| | + LL| |trait MyTrait { + LL| | fn trait_method(&self); + LL| |} + LL| |impl MyTrait for MyOuter { + LL| | #[coverage(off)] + LL| | fn trait_method(&self) { + LL| | struct MyMiddle; + LL| | impl MyTrait for MyMiddle { + LL| 0| fn trait_method(&self) { + LL| 0| struct MyInner; + LL| 0| impl MyTrait for MyInner { + LL| 0| fn trait_method(&self) { + LL| 0| do_stuff(); + LL| 0| } + LL| 0| } + LL| 0| do_stuff(); + LL| 0| } + LL| | } + LL| | do_stuff(); + LL| | } + LL| |} + LL| | + LL| 1|fn closure_expr() { + LL| 1| let _outer = #[coverage(off)] + LL| | || { + LL| 0| let _middle = || { + LL| 0| let _inner = || { + LL| 0| do_stuff(); + LL| 0| }; + LL| 0| do_stuff(); + LL| 0| }; + LL| | do_stuff(); + LL| | }; + LL| 1| do_stuff(); + LL| 1|} + LL| | + LL| |// This syntax is allowed, even without #![feature(stmt_expr_attributes)]. + LL| 1|fn closure_tail() { + LL| 1| let _outer = { + LL| | #[coverage(off)] + LL| | || { + LL| | let _middle = { + LL| 0| || { + LL| 0| let _inner = { + LL| 0| || { + LL| 0| do_stuff(); + LL| 0| } + LL| | }; + LL| 0| do_stuff(); + LL| 0| } + LL| | }; + LL| | do_stuff(); + LL| | } + LL| | }; + LL| 1| do_stuff(); + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | outer_fn(); + LL| | MyOuter.outer_method(); + LL| | MyOuter.trait_method(); + LL| | closure_expr(); + LL| | closure_tail(); + LL| |} + diff --git a/tests/coverage/attr/nested.rs b/tests/coverage/attr/nested.rs new file mode 100644 index 000000000000..c7ff835f44f3 --- /dev/null +++ b/tests/coverage/attr/nested.rs @@ -0,0 +1,110 @@ +#![feature(coverage_attribute, stmt_expr_attributes)] +//@ edition: 2021 + +// Demonstrates the interaction between #[coverage(off)] and various kinds of +// nested function. + +// FIXME(#126625): Coverage attributes should apply recursively to nested functions. +// FIXME(#126626): When an inner (non-closure) function has `#[coverage(off)]`, +// its lines can still be marked with misleading execution counts from its enclosing +// function. + +#[coverage(off)] +fn do_stuff() {} + +#[coverage(off)] +fn outer_fn() { + fn middle_fn() { + fn inner_fn() { + do_stuff(); + } + do_stuff(); + } + do_stuff(); +} + +struct MyOuter; +impl MyOuter { + #[coverage(off)] + fn outer_method(&self) { + struct MyMiddle; + impl MyMiddle { + fn middle_method(&self) { + struct MyInner; + impl MyInner { + fn inner_method(&self) { + do_stuff(); + } + } + do_stuff(); + } + } + do_stuff(); + } +} + +trait MyTrait { + fn trait_method(&self); +} +impl MyTrait for MyOuter { + #[coverage(off)] + fn trait_method(&self) { + struct MyMiddle; + impl MyTrait for MyMiddle { + fn trait_method(&self) { + struct MyInner; + impl MyTrait for MyInner { + fn trait_method(&self) { + do_stuff(); + } + } + do_stuff(); + } + } + do_stuff(); + } +} + +fn closure_expr() { + let _outer = #[coverage(off)] + || { + let _middle = || { + let _inner = || { + do_stuff(); + }; + do_stuff(); + }; + do_stuff(); + }; + do_stuff(); +} + +// This syntax is allowed, even without #![feature(stmt_expr_attributes)]. +fn closure_tail() { + let _outer = { + #[coverage(off)] + || { + let _middle = { + || { + let _inner = { + || { + do_stuff(); + } + }; + do_stuff(); + } + }; + do_stuff(); + } + }; + do_stuff(); +} + +#[coverage(off)] +fn main() { + outer_fn(); + MyOuter.outer_method(); + MyOuter.trait_method(); + closure_expr(); + closure_tail(); +} diff --git a/tests/coverage/attr/off-on-sandwich.cov-map b/tests/coverage/attr/off-on-sandwich.cov-map new file mode 100644 index 000000000000..72b96420cb56 --- /dev/null +++ b/tests/coverage/attr/off-on-sandwich.cov-map @@ -0,0 +1,32 @@ +Function name: off_on_sandwich::dense_a::dense_b +Raw bytes (9): 0x[01, 01, 00, 01, 01, 14, 05, 07, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 20, 5) to (start + 7, 6) + +Function name: off_on_sandwich::sparse_a::sparse_b +Raw bytes (9): 0x[01, 01, 00, 01, 01, 22, 05, 10, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 34, 5) to (start + 16, 6) + +Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c +Raw bytes (9): 0x[01, 01, 00, 01, 01, 26, 09, 0b, 0a] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 38, 9) to (start + 11, 10) + +Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c::sparse_d +Raw bytes (9): 0x[01, 01, 00, 01, 01, 29, 0d, 07, 0e] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 41, 13) to (start + 7, 14) + diff --git a/tests/coverage/attr/off-on-sandwich.coverage b/tests/coverage/attr/off-on-sandwich.coverage new file mode 100644 index 000000000000..e831b0e926e3 --- /dev/null +++ b/tests/coverage/attr/off-on-sandwich.coverage @@ -0,0 +1,58 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| | + LL| |// Demonstrates the interaction of `#[coverage(off)]` and `#[coverage(on)]` + LL| |// in nested functions. + LL| | + LL| |// FIXME(#126625): Coverage attributes should apply recursively to nested functions. + LL| |// FIXME(#126626): When an inner (non-closure) function has `#[coverage(off)]`, + LL| |// its lines can still be marked with misleading execution counts from its enclosing + LL| |// function. + LL| | + LL| |#[coverage(off)] + LL| |fn do_stuff() {} + LL| | + LL| |#[coverage(off)] + LL| |fn dense_a() { + LL| | dense_b(); + LL| | dense_b(); + LL| | #[coverage(on)] + LL| 2| fn dense_b() { + LL| 2| dense_c(); + LL| 2| dense_c(); + LL| 2| #[coverage(off)] + LL| 2| fn dense_c() { + LL| 2| do_stuff(); + LL| 2| } + LL| 2| } + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn sparse_a() { + LL| | sparse_b(); + LL| | sparse_b(); + LL| 2| fn sparse_b() { + LL| 2| sparse_c(); + LL| 2| sparse_c(); + LL| 2| #[coverage(on)] + LL| 4| fn sparse_c() { + LL| 4| sparse_d(); + LL| 4| sparse_d(); + LL| 8| fn sparse_d() { + LL| 8| sparse_e(); + LL| 8| sparse_e(); + LL| 8| #[coverage(off)] + LL| 8| fn sparse_e() { + LL| 8| do_stuff(); + LL| 8| } + LL| 8| } + LL| 4| } + LL| 2| } + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | dense_a(); + LL| | sparse_a(); + LL| |} + diff --git a/tests/coverage/attr/off-on-sandwich.rs b/tests/coverage/attr/off-on-sandwich.rs new file mode 100644 index 000000000000..6b21b180223e --- /dev/null +++ b/tests/coverage/attr/off-on-sandwich.rs @@ -0,0 +1,57 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 + +// Demonstrates the interaction of `#[coverage(off)]` and `#[coverage(on)]` +// in nested functions. + +// FIXME(#126625): Coverage attributes should apply recursively to nested functions. +// FIXME(#126626): When an inner (non-closure) function has `#[coverage(off)]`, +// its lines can still be marked with misleading execution counts from its enclosing +// function. + +#[coverage(off)] +fn do_stuff() {} + +#[coverage(off)] +fn dense_a() { + dense_b(); + dense_b(); + #[coverage(on)] + fn dense_b() { + dense_c(); + dense_c(); + #[coverage(off)] + fn dense_c() { + do_stuff(); + } + } +} + +#[coverage(off)] +fn sparse_a() { + sparse_b(); + sparse_b(); + fn sparse_b() { + sparse_c(); + sparse_c(); + #[coverage(on)] + fn sparse_c() { + sparse_d(); + sparse_d(); + fn sparse_d() { + sparse_e(); + sparse_e(); + #[coverage(off)] + fn sparse_e() { + do_stuff(); + } + } + } + } +} + +#[coverage(off)] +fn main() { + dense_a(); + sparse_a(); +} diff --git a/tests/coverage/branch/no-mir-spans.cov-map b/tests/coverage/branch/no-mir-spans.cov-map new file mode 100644 index 000000000000..cb19211913f8 --- /dev/null +++ b/tests/coverage/branch/no-mir-spans.cov-map @@ -0,0 +1,52 @@ +Function name: no_mir_spans::while_cond +Raw bytes (16): 0x[01, 01, 00, 02, 01, 10, 01, 00, 11, 20, 05, 09, 04, 0b, 00, 10] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 17) +- Branch { true: Counter(1), false: Counter(2) } at (prev + 4, 11) to (start + 0, 16) + true = c1 + false = c2 + +Function name: no_mir_spans::while_cond_not +Raw bytes (16): 0x[01, 01, 00, 02, 01, 19, 01, 00, 15, 20, 09, 05, 04, 0b, 00, 14] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 25, 1) to (start + 0, 21) +- Branch { true: Counter(2), false: Counter(1) } at (prev + 4, 11) to (start + 0, 20) + true = c2 + false = c1 + +Function name: no_mir_spans::while_op_and +Raw bytes (25): 0x[01, 01, 01, 09, 0d, 03, 01, 22, 01, 00, 13, 20, 09, 05, 05, 0b, 00, 10, 20, 02, 0d, 00, 14, 00, 19] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 34, 1) to (start + 0, 19) +- Branch { true: Counter(2), false: Counter(1) } at (prev + 5, 11) to (start + 0, 16) + true = c2 + false = c1 +- Branch { true: Expression(0, Sub), false: Counter(3) } at (prev + 0, 20) to (start + 0, 25) + true = (c2 - c3) + false = c3 + +Function name: no_mir_spans::while_op_or +Raw bytes (25): 0x[01, 01, 01, 09, 0d, 03, 01, 2d, 01, 00, 12, 20, 05, 09, 05, 0b, 00, 10, 20, 0d, 02, 00, 14, 00, 19] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 45, 1) to (start + 0, 18) +- Branch { true: Counter(1), false: Counter(2) } at (prev + 5, 11) to (start + 0, 16) + true = c1 + false = c2 +- Branch { true: Counter(3), false: Expression(0, Sub) } at (prev + 0, 20) to (start + 0, 25) + true = c3 + false = (c2 - c3) + diff --git a/tests/coverage/branch/no-mir-spans.coverage b/tests/coverage/branch/no-mir-spans.coverage new file mode 100644 index 000000000000..2cae98ed3ff4 --- /dev/null +++ b/tests/coverage/branch/no-mir-spans.coverage @@ -0,0 +1,77 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| |//@ compile-flags: -Zcoverage-options=branch,no-mir-spans + LL| |//@ llvm-cov-flags: --show-branches=count + LL| | + LL| |// Tests the behaviour of the `-Zcoverage-options=no-mir-spans` debugging flag. + LL| |// The actual code below is just some non-trivial code copied from another test + LL| |// (`while.rs`), and has no particular significance. + LL| | + LL| |macro_rules! no_merge { + LL| | () => { + LL| | for _ in 0..1 {} + LL| | }; + LL| |} + LL| | + LL| 1|fn while_cond() { + LL| | no_merge!(); + LL| | + LL| | let mut a = 8; + LL| | while a > 0 { + ------------------ + | Branch (LL:11): [True: 8, False: 1] + ------------------ + LL| | a -= 1; + LL| | } + LL| |} + LL| | + LL| 1|fn while_cond_not() { + LL| | no_merge!(); + LL| | + LL| | let mut a = 8; + LL| | while !(a == 0) { + ------------------ + | Branch (LL:11): [True: 8, False: 1] + ------------------ + LL| | a -= 1; + LL| | } + LL| |} + LL| | + LL| 1|fn while_op_and() { + LL| | no_merge!(); + LL| | + LL| | let mut a = 8; + LL| | let mut b = 4; + LL| | while a > 0 && b > 0 { + ------------------ + | Branch (LL:11): [True: 5, False: 0] + | Branch (LL:20): [True: 4, False: 1] + ------------------ + LL| | a -= 1; + LL| | b -= 1; + LL| | } + LL| |} + LL| | + LL| 1|fn while_op_or() { + LL| | no_merge!(); + LL| | + LL| | let mut a = 4; + LL| | let mut b = 8; + LL| | while a > 0 || b > 0 { + ------------------ + | Branch (LL:11): [True: 4, False: 5] + | Branch (LL:20): [True: 4, False: 1] + ------------------ + LL| | a -= 1; + LL| | b -= 1; + LL| | } + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | while_cond(); + LL| | while_cond_not(); + LL| | while_op_and(); + LL| | while_op_or(); + LL| |} + diff --git a/tests/coverage/branch/no-mir-spans.rs b/tests/coverage/branch/no-mir-spans.rs new file mode 100644 index 000000000000..acb268f2d455 --- /dev/null +++ b/tests/coverage/branch/no-mir-spans.rs @@ -0,0 +1,62 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 +//@ compile-flags: -Zcoverage-options=branch,no-mir-spans +//@ llvm-cov-flags: --show-branches=count + +// Tests the behaviour of the `-Zcoverage-options=no-mir-spans` debugging flag. +// The actual code below is just some non-trivial code copied from another test +// (`while.rs`), and has no particular significance. + +macro_rules! no_merge { + () => { + for _ in 0..1 {} + }; +} + +fn while_cond() { + no_merge!(); + + let mut a = 8; + while a > 0 { + a -= 1; + } +} + +fn while_cond_not() { + no_merge!(); + + let mut a = 8; + while !(a == 0) { + a -= 1; + } +} + +fn while_op_and() { + no_merge!(); + + let mut a = 8; + let mut b = 4; + while a > 0 && b > 0 { + a -= 1; + b -= 1; + } +} + +fn while_op_or() { + no_merge!(); + + let mut a = 4; + let mut b = 8; + while a > 0 || b > 0 { + a -= 1; + b -= 1; + } +} + +#[coverage(off)] +fn main() { + while_cond(); + while_cond_not(); + while_op_and(); + while_op_or(); +} diff --git a/tests/run-make/allocator-shim-circular-deps/Makefile b/tests/run-make/allocator-shim-circular-deps/Makefile deleted file mode 100644 index f667e2e2ec29..000000000000 --- a/tests/run-make/allocator-shim-circular-deps/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# This test is designed to intentionally introduce a circular dependency scenario to check that a specific compiler bug doesn't make a resurgence. -# The bug in question arose when at least one crate required a global allocator, and that crate was placed after the one defining it in the linker order. -# The generated symbols.o should not result in any linker errors. -# See https://github.com/rust-lang/rust/issues/112715 - -# ignore-cross-compile -include ../tools.mk - -all: - rm -rf $(TMPDIR) && mkdir $(TMPDIR) - $(RUSTC) my_lib.rs - $(RUSTC) main.rs --test --extern my_lib=$(TMPDIR)/libmy_lib.rlib diff --git a/tests/run-make/allocator-shim-circular-deps/rmake.rs b/tests/run-make/allocator-shim-circular-deps/rmake.rs new file mode 100644 index 000000000000..7d6b0bd204a1 --- /dev/null +++ b/tests/run-make/allocator-shim-circular-deps/rmake.rs @@ -0,0 +1,16 @@ +// This test is designed to intentionally introduce a circular dependency scenario to check +// that a specific compiler bug doesn't make a resurgence. +// The bug in question arose when at least one crate +// required a global allocator, and that crate was placed after +// the one defining it in the linker order. +// The generated symbols.o should not result in any linker errors. +// See https://github.com/rust-lang/rust/issues/112715 + +//@ ignore-cross-compile + +use run_make_support::{rust_lib_name, rustc}; + +fn main() { + rustc().input("my_lib.rs").run(); + rustc().input("main.rs").arg("--test").extern_("my_lib", rust_lib_name("my_lib")).run(); +} diff --git a/tests/run-make/error-found-staticlib-instead-crate/Makefile b/tests/run-make/error-found-staticlib-instead-crate/Makefile deleted file mode 100644 index 0eae41d720cc..000000000000 --- a/tests/run-make/error-found-staticlib-instead-crate/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) foo.rs --crate-type staticlib - $(RUSTC) bar.rs 2>&1 | $(CGREP) "found staticlib" diff --git a/tests/run-make/error-found-staticlib-instead-crate/rmake.rs b/tests/run-make/error-found-staticlib-instead-crate/rmake.rs new file mode 100644 index 000000000000..8c707092b7e4 --- /dev/null +++ b/tests/run-make/error-found-staticlib-instead-crate/rmake.rs @@ -0,0 +1,11 @@ +// When rustc is looking for a crate but is given a staticlib instead, +// the error message should be helpful and indicate precisely the cause +// of the compilation failure. +// See https://github.com/rust-lang/rust/pull/21978 + +use run_make_support::rustc; + +fn main() { + rustc().input("foo.rs").crate_type("staticlib").run(); + rustc().input("bar.rs").run_fail().assert_stderr_contains("found staticlib"); +} diff --git a/tests/run-make/extern-flag-fun/Makefile b/tests/run-make/extern-flag-fun/Makefile deleted file mode 100644 index 687cdfd76755..000000000000 --- a/tests/run-make/extern-flag-fun/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) bar.rs --crate-type=rlib - $(RUSTC) bar.rs --crate-type=rlib -C extra-filename=-a - $(RUSTC) bar-alt.rs --crate-type=rlib - $(RUSTC) foo.rs --extern bar=no-exist && exit 1 || exit 0 - $(RUSTC) foo.rs --extern bar=foo.rs && exit 1 || exit 0 - $(RUSTC) foo.rs \ - --extern bar=$(TMPDIR)/libbar.rlib \ - --extern bar=$(TMPDIR)/libbar-alt.rlib \ - && exit 1 || exit 0 - $(RUSTC) foo.rs \ - --extern bar=$(TMPDIR)/libbar.rlib \ - --extern bar=$(TMPDIR)/libbar-a.rlib - $(RUSTC) foo.rs --extern bar=$(TMPDIR)/libbar.rlib - # Try to be sneaky and load a private crate from with a non-private name. - $(RUSTC) rustc.rs -Zforce-unstable-if-unmarked --crate-type=rlib - $(RUSTC) gated_unstable.rs --extern alloc=$(TMPDIR)/librustc.rlib 2>&1 | $(CGREP) 'rustc_private' diff --git a/tests/run-make/extern-flag-fun/rmake.rs b/tests/run-make/extern-flag-fun/rmake.rs new file mode 100644 index 000000000000..c1825f6bbb88 --- /dev/null +++ b/tests/run-make/extern-flag-fun/rmake.rs @@ -0,0 +1,38 @@ +// The --extern flag can override the default crate search of +// the compiler and directly fetch a given path. There are a few rules +// to follow: for example, there can't be more than one rlib, the crates must +// be valid ("no-exist" in this test), and private crates can't be loaded +// as non-private. This test checks that these rules are enforced. +// See https://github.com/rust-lang/rust/pull/15319 + +use run_make_support::{rust_lib_name, rustc}; + +fn main() { + rustc().input("bar.rs").crate_type("rlib").run(); + // Exactly the same rlib as the first line, only the filename changes. + rustc().input("bar.rs").crate_type("rlib").extra_filename("-a").run(); + rustc().input("bar-alt.rs").crate_type("rlib").run(); + // The crate must be valid. + rustc().input("foo.rs").extern_("bar", "no-exist").run_fail(); + rustc().input("foo.rs").extern_("bar", "foo.rs").run_fail(); + // Compilation fails with two different rlibs. + rustc() + .input("foo.rs") + .extern_("bar", rust_lib_name("bar")) + .extern_("bar", rust_lib_name("bar-alt")) + .run_fail(); + // Even though this one has seemingly two rlibs, they are one and the same. + rustc() + .input("foo.rs") + .extern_("bar", rust_lib_name("bar")) + .extern_("bar", rust_lib_name("bar-a")) + .run(); + rustc().input("foo.rs").extern_("bar", rust_lib_name("bar")).run(); + // Try to be sneaky and load a private crate from with a non-private name. + rustc().input("rustc.rs").arg("-Zforce-unstable-if-unmarked").crate_type("rlib").run(); + rustc() + .input("gated_unstable.rs") + .extern_("alloc", rust_lib_name("rustc")) + .run_fail() + .assert_stderr_contains("rustc_private"); +} diff --git a/tests/run-make/incremental-debugger-visualizer/Makefile b/tests/run-make/incremental-debugger-visualizer/Makefile deleted file mode 100644 index 8cfe41597adf..000000000000 --- a/tests/run-make/incremental-debugger-visualizer/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -include ../tools.mk - -# This test makes sure that changes to files referenced via #[debugger_visualizer] -# are picked up when compiling incrementally. - -# We have to copy the source to $(TMPDIR) because Github CI mounts the source -# directory as readonly. We need to apply modifications to some of the source -# file. -SRC_DIR := $(TMPDIR)/src -INCR_CACHE_DIR := $(TMPDIR)/incremental - -all: - rm -rf $(TMPDIR)/* - mkdir $(SRC_DIR) - cp ./foo.rs $(SRC_DIR) - echo "GDB script v1" > $(SRC_DIR)/foo.py - echo "Natvis v1" > $(SRC_DIR)/foo.natvis - $(RUSTC) $(SRC_DIR)/foo.rs \ - --crate-type=rlib \ - --emit metadata \ - -C incremental=$(INCR_CACHE_DIR) \ - -Z incremental-verify-ich - $(CGREP) "GDB script v1" < $(TMPDIR)/libfoo.rmeta - $(CGREP) "Natvis v1" < $(TMPDIR)/libfoo.rmeta - - # Change only the GDB script and check that the change has been picked up - echo "GDB script v2" > $(SRC_DIR)/foo.py - $(RUSTC) $(SRC_DIR)/foo.rs \ - --crate-type=rlib \ - --emit metadata \ - -C incremental=$(INCR_CACHE_DIR) \ - -Z incremental-verify-ich - - $(CGREP) "GDB script v2" < $(TMPDIR)/libfoo.rmeta - $(CGREP) -v "GDB script v1" < $(TMPDIR)/libfoo.rmeta - $(CGREP) "Natvis v1" < $(TMPDIR)/libfoo.rmeta - - # Now change the Natvis version and check that the change has been picked up - echo "Natvis v2" > $(SRC_DIR)/foo.natvis - $(RUSTC) $(SRC_DIR)/foo.rs \ - --crate-type=rlib \ - --emit metadata \ - -C incremental=$(INCR_CACHE_DIR) \ - -Z incremental-verify-ich - - $(CGREP) "GDB script v2" < $(TMPDIR)/libfoo.rmeta - $(CGREP) -v "GDB script v1" < $(TMPDIR)/libfoo.rmeta - $(CGREP) "Natvis v2" < $(TMPDIR)/libfoo.rmeta - $(CGREP) -v "Natvis v1" < $(TMPDIR)/libfoo.rmeta diff --git a/tests/run-make/incremental-debugger-visualizer/rmake.rs b/tests/run-make/incremental-debugger-visualizer/rmake.rs new file mode 100644 index 000000000000..1ef3af873530 --- /dev/null +++ b/tests/run-make/incremental-debugger-visualizer/rmake.rs @@ -0,0 +1,56 @@ +// This test ensures that changes to files referenced via #[debugger_visualizer] +// (in this case, foo.py and foo.natvis) are picked up when compiling incrementally. +// See https://github.com/rust-lang/rust/pull/111641 + +use run_make_support::{fs_wrapper, invalid_utf8_contains, invalid_utf8_not_contains, rustc}; +use std::io::Read; + +fn main() { + fs_wrapper::create_file("foo.py"); + fs_wrapper::write("foo.py", "GDB script v1"); + fs_wrapper::create_file("foo.natvis"); + fs_wrapper::write("foo.natvis", "Natvis v1"); + rustc() + .input("foo.rs") + .crate_type("rlib") + .emit("metadata") + .incremental("incremental") + .arg("-Zincremental-verify-ich") + .run(); + + invalid_utf8_contains("libfoo.rmeta", "GDB script v1"); + invalid_utf8_contains("libfoo.rmeta", "Natvis v1"); + + // Change only the GDB script and check that the change has been picked up + fs_wrapper::remove_file("foo.py"); + fs_wrapper::create_file("foo.py"); + fs_wrapper::write("foo.py", "GDB script v2"); + rustc() + .input("foo.rs") + .crate_type("rlib") + .emit("metadata") + .incremental("incremental") + .arg("-Zincremental-verify-ich") + .run(); + + invalid_utf8_contains("libfoo.rmeta", "GDB script v2"); + invalid_utf8_not_contains("libfoo.rmeta", "GDB script v1"); + invalid_utf8_contains("libfoo.rmeta", "Natvis v1"); + + // Now change the Natvis version and check that the change has been picked up + fs_wrapper::remove_file("foo.natvis"); + fs_wrapper::create_file("foo.natvis"); + fs_wrapper::write("foo.natvis", "Natvis v2"); + rustc() + .input("foo.rs") + .crate_type("rlib") + .emit("metadata") + .incremental("incremental") + .arg("-Zincremental-verify-ich") + .run(); + + invalid_utf8_contains("libfoo.rmeta", "GDB script v2"); + invalid_utf8_not_contains("libfoo.rmeta", "GDB script v1"); + invalid_utf8_not_contains("libfoo.rmeta", "Natvis v1"); + invalid_utf8_contains("libfoo.rmeta", "Natvis v2"); +} diff --git a/tests/run-make/incremental-session-fail/Makefile b/tests/run-make/incremental-session-fail/Makefile deleted file mode 100644 index f43eece2eb70..000000000000 --- a/tests/run-make/incremental-session-fail/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -include ../tools.mk - -SESSION_DIR := $(TMPDIR)/session -OUTPUT_FILE := $(TMPDIR)/build-output - -all: - echo $(TMPDIR) - # Make it so that rustc will fail to create a session directory. - touch $(SESSION_DIR) - # Check exit code is 1 for an error, and not 101 for ICE. - $(RUSTC) foo.rs --crate-type=rlib -C incremental=$(SESSION_DIR) > $(OUTPUT_FILE) 2>&1; [ $$? -eq 1 ] - $(CGREP) "could not create incremental compilation crate directory" < $(OUTPUT_FILE) - # -v tests are fragile, hopefully this text won't change - $(CGREP) -v "internal compiler error" < $(OUTPUT_FILE) diff --git a/tests/run-make/incremental-session-fail/rmake.rs b/tests/run-make/incremental-session-fail/rmake.rs new file mode 100644 index 000000000000..0283709f2cf8 --- /dev/null +++ b/tests/run-make/incremental-session-fail/rmake.rs @@ -0,0 +1,15 @@ +// Failing to create the directory where output incremental +// files would be stored used to cause an ICE (Internal Compiler +// Error). This was patched in #85698, and this test checks that +// the ensuing compilation failure is not an ICE. +// See https://github.com/rust-lang/rust/pull/85698 + +use run_make_support::{fs_wrapper, rustc}; + +fn main() { + fs_wrapper::create_file("session"); + // rustc should fail to create the session directory here. + let out = rustc().input("foo.rs").crate_type("rlib").incremental("session").run_fail(); + out.assert_stderr_contains("could not create incremental compilation crate directory"); + out.assert_stderr_not_contains("internal compiler error"); +} diff --git a/tests/run-make/invalid-staticlib/Makefile b/tests/run-make/invalid-staticlib/Makefile deleted file mode 100644 index 3f0f74ce3cb0..000000000000 --- a/tests/run-make/invalid-staticlib/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -include ../tools.mk - -all: - touch $(TMPDIR)/libfoo.a - echo | $(RUSTC) - --crate-type=rlib -lstatic=foo 2>&1 | $(CGREP) "failed to add native library" diff --git a/tests/run-make/invalid-staticlib/rmake.rs b/tests/run-make/invalid-staticlib/rmake.rs new file mode 100644 index 000000000000..451292932477 --- /dev/null +++ b/tests/run-make/invalid-staticlib/rmake.rs @@ -0,0 +1,17 @@ +// If the static library provided is not valid (in this test, +// created as an empty file), +// rustc should print a normal error message and not throw +// an internal compiler error (ICE). +// See https://github.com/rust-lang/rust/pull/28673 + +use run_make_support::{fs_wrapper, rustc, static_lib_name}; + +fn main() { + fs_wrapper::create_file(static_lib_name("foo")); + rustc() + .arg("-") + .crate_type("rlib") + .arg("-lstatic=foo") + .run_fail() + .assert_stderr_contains("failed to add native library"); +} diff --git a/tests/run-make/issue-64153/Makefile b/tests/run-make/issue-64153/Makefile deleted file mode 100644 index f42ea620fb9d..000000000000 --- a/tests/run-make/issue-64153/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -include ../tools.mk - -# `llvm-objdump`'s output looks different on windows than on other platforms. -# It should be enough to check on Unix platforms, so: -# ignore-windows - -# Staticlibs don't include Rust object files from upstream crates if the same -# code was already pulled into the lib via LTO. However, the bug described in -# https://github.com/rust-lang/rust/issues/64153 lead to this exclusion not -# working properly if the upstream crate was compiled with an explicit filename -# (via `-o`). -# -# This test makes sure that functions defined in the upstream crates do not -# appear twice in the final staticlib when listing all the symbols from it. - -all: - $(RUSTC) --crate-type rlib upstream.rs -o $(TMPDIR)/libupstream.rlib -Ccodegen-units=1 - $(RUSTC) --crate-type staticlib downstream.rs -Clto -Ccodegen-units=1 -o $(TMPDIR)/libdownstream.a - # Dump all the symbols from the staticlib into `syms` - "$(LLVM_BIN_DIR)"/llvm-objdump -t $(TMPDIR)/libdownstream.a > $(TMPDIR)/syms - # Count the global instances of `issue64153_test_function`. There'll be 2 - # if the `upstream` object file got erroneously included twice. - # The line we are testing for with the regex looks something like: - # 0000000000000000 g F .text.issue64153_test_function 00000023 issue64153_test_function - grep -c -e "[[:space:]]g[[:space:]]*F[[:space:]].*issue64153_test_function" $(TMPDIR)/syms > $(TMPDIR)/count - [ "$$(cat $(TMPDIR)/count)" -eq "1" ] diff --git a/tests/run-make/issue-64153/downstream.rs b/tests/run-make/lto-avoid-object-duplication/downstream.rs similarity index 100% rename from tests/run-make/issue-64153/downstream.rs rename to tests/run-make/lto-avoid-object-duplication/downstream.rs diff --git a/tests/run-make/lto-avoid-object-duplication/rmake.rs b/tests/run-make/lto-avoid-object-duplication/rmake.rs new file mode 100644 index 000000000000..b0e7494cb513 --- /dev/null +++ b/tests/run-make/lto-avoid-object-duplication/rmake.rs @@ -0,0 +1,40 @@ +// ignore-tidy-tab +// Staticlibs don't include Rust object files from upstream crates if the same +// code was already pulled into the lib via LTO. However, the bug described in +// https://github.com/rust-lang/rust/issues/64153 lead to this exclusion not +// working properly if the upstream crate was compiled with an explicit filename +// (via `-o`). + +// This test makes sure that functions defined in the upstream crates do not +// appear twice in the final staticlib when listing all the symbols from it. + +//@ ignore-windows +// Reason: `llvm-objdump`'s output looks different on windows than on other platforms. +// Only checking on Unix platforms should suffice. +//FIXME(Oneirical): This could be adapted to work on Windows by checking how +// that output differs. + +use run_make_support::{llvm_objdump, regex, rust_lib_name, rustc, static_lib_name}; + +fn main() { + rustc() + .crate_type("rlib") + .input("upstream.rs") + .output(rust_lib_name("upstream")) + .codegen_units(1) + .run(); + rustc() + .crate_type("staticlib") + .input("downstream.rs") + .arg("-Clto") + .output(static_lib_name("downstream")) + .codegen_units(1) + .run(); + let syms = llvm_objdump().arg("-t").input(static_lib_name("downstream")).run().stdout_utf8(); + let re = regex::Regex::new(r#"\s*g\s*F\s.*issue64153_test_function"#).unwrap(); + // Count the global instances of `issue64153_test_function`. There'll be 2 + // if the `upstream` object file got erroneously included twice. + // The line we are testing for with the regex looks something like: + // 0000000000000000 g F .text.issue64153_test_function 00000023 issue64153_test_function + assert_eq!(re.find_iter(syms.as_str()).count(), 1); +} diff --git a/tests/run-make/issue-64153/upstream.rs b/tests/run-make/lto-avoid-object-duplication/upstream.rs similarity index 100% rename from tests/run-make/issue-64153/upstream.rs rename to tests/run-make/lto-avoid-object-duplication/upstream.rs diff --git a/tests/run-make/native-link-modifier-verbatim-linker/Makefile b/tests/run-make/native-link-modifier-verbatim-linker/Makefile deleted file mode 100644 index 47ed2a142918..000000000000 --- a/tests/run-make/native-link-modifier-verbatim-linker/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# ignore-cross-compile -# ignore-apple - -include ../tools.mk - -all: - # Verbatim allows specify precise name. - $(RUSTC) local_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/local_some_strange_name.ext - $(RUSTC) main.rs -l static:+verbatim=local_some_strange_name.ext - - # With verbatim any other name cannot be used (local). - $(RUSTC) local_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/liblocal_native_dep.a - $(RUSTC) local_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/local_native_dep.a - $(RUSTC) local_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/local_native_dep.lib - $(RUSTC) main.rs -l static:+verbatim=local_native_dep 2>&1 | $(CGREP) "local_native_dep" diff --git a/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs b/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs new file mode 100644 index 000000000000..6868cb368ccc --- /dev/null +++ b/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs @@ -0,0 +1,41 @@ +// `verbatim` is a native link modifier that forces rustc to only accept libraries with +// a specified name. This test checks that this modifier works as intended. +// This test is the same as native-link-modifier-rustc, but without rlibs. +// See https://github.com/rust-lang/rust/issues/99425 + +//@ ignore-apple +// Reason: linking fails due to the unusual ".ext" staticlib name. + +use run_make_support::rustc; + +fn main() { + // Verbatim allows for the specification of a precise name + // - in this case, the unconventional ".ext" extension. + rustc() + .input("local_native_dep.rs") + .crate_type("staticlib") + .output("local_some_strange_name.ext") + .run(); + rustc().input("main.rs").arg("-lstatic:+verbatim=local_some_strange_name.ext").run(); + + // This section voluntarily avoids using static_lib_name helpers to be verbatim. + // With verbatim, even these common library names are refused + // - it wants local_native_dep without + // any file extensions. + rustc() + .input("local_native_dep.rs") + .crate_type("staticlib") + .output("liblocal_native_dep.a") + .run(); + rustc().input("local_native_dep.rs").crate_type("staticlib").output("local_native_dep.a").run(); + rustc() + .input("local_native_dep.rs") + .crate_type("staticlib") + .output("local_native_dep.lib") + .run(); + rustc() + .input("main.rs") + .arg("-lstatic:+verbatim=local_native_dep") + .run_fail() + .assert_stderr_contains("local_native_dep"); +} diff --git a/tests/run-make/native-link-modifier-verbatim-rustc/Makefile b/tests/run-make/native-link-modifier-verbatim-rustc/Makefile deleted file mode 100644 index dfd6ec50fc00..000000000000 --- a/tests/run-make/native-link-modifier-verbatim-rustc/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include ../tools.mk - -all: - # Verbatim allows specify precise name. - $(RUSTC) upstream_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/upstream_some_strange_name.ext - $(RUSTC) rust_dep.rs -l static:+verbatim=upstream_some_strange_name.ext --crate-type rlib - - # With verbatim any other name cannot be used (upstream). - $(RUSTC) upstream_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/libupstream_native_dep.a - $(RUSTC) upstream_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/upstream_native_dep.a - $(RUSTC) upstream_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/upstream_native_dep.lib - $(RUSTC) rust_dep.rs -l static:+verbatim=upstream_native_dep --crate-type rlib 2>&1 | $(CGREP) "upstream_native_dep" diff --git a/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs b/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs new file mode 100644 index 000000000000..703b8a80ef3e --- /dev/null +++ b/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs @@ -0,0 +1,47 @@ +// `verbatim` is a native link modifier that forces rustc to only accept libraries with +// a specified name. This test checks that this modifier works as intended. +// This test is the same as native-link-modifier-linker, but with rlibs. +// See https://github.com/rust-lang/rust/issues/99425 + +use run_make_support::rustc; + +fn main() { + // Verbatim allows for the specification of a precise name + // - in this case, the unconventional ".ext" extension. + rustc() + .input("upstream_native_dep.rs") + .crate_type("staticlib") + .output("upstream_some_strange_name.ext") + .run(); + rustc() + .input("rust_dep.rs") + .crate_type("rlib") + .arg("-lstatic:+verbatim=upstream_some_strange_name.ext") + .run(); + + // This section voluntarily avoids using static_lib_name helpers to be verbatim. + // With verbatim, even these common library names are refused + // - it wants upstream_native_dep without + // any file extensions. + rustc() + .input("upstream_native_dep.rs") + .crate_type("staticlib") + .output("libupstream_native_dep.a") + .run(); + rustc() + .input("upstream_native_dep.rs") + .crate_type("staticlib") + .output("upstream_native_dep.a") + .run(); + rustc() + .input("upstream_native_dep.rs") + .crate_type("staticlib") + .output("upstream_native_dep.lib") + .run(); + rustc() + .input("rust_dep.rs") + .crate_type("rlib") + .arg("-lstatic:+verbatim=upstream_native_dep") + .run_fail() + .assert_stderr_contains("upstream_native_dep"); +} diff --git a/tests/run-make/no-builtins-lto/Makefile b/tests/run-make/no-builtins-lto/Makefile deleted file mode 100644 index c8f05d9918b9..000000000000 --- a/tests/run-make/no-builtins-lto/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -include ../tools.mk - -all: - # Compile a `#![no_builtins]` rlib crate - $(RUSTC) no_builtins.rs - # Build an executable that depends on that crate using LTO. The no_builtins crate doesn't - # participate in LTO, so its rlib must be explicitly linked into the final binary. Verify this by - # grepping the linker arguments. - $(RUSTC) main.rs -C lto --print link-args | $(CGREP) 'libno_builtins.rlib' diff --git a/tests/run-make/no-builtins-lto/rmake.rs b/tests/run-make/no-builtins-lto/rmake.rs new file mode 100644 index 000000000000..8e0c3a636490 --- /dev/null +++ b/tests/run-make/no-builtins-lto/rmake.rs @@ -0,0 +1,20 @@ +// The rlib produced by a no_builtins crate should be explicitely linked +// during compilation, and as a result be present in the linker arguments. +// See the comments inside this file for more details. +// See https://github.com/rust-lang/rust/pull/35637 + +use run_make_support::{rust_lib_name, rustc}; + +fn main() { + // Compile a `#![no_builtins]` rlib crate + rustc().input("no_builtins.rs").run(); + // Build an executable that depends on that crate using LTO. The no_builtins crate doesn't + // participate in LTO, so its rlib must be explicitly + // linked into the final binary. Verify this by grepping the linker arguments. + rustc() + .input("main.rs") + .arg("-Clto") + .print("link-args") + .run() + .assert_stdout_contains(rust_lib_name("no_builtins")); +} diff --git a/tests/run-make/output-filename-conflicts-with-directory/Makefile b/tests/run-make/output-filename-conflicts-with-directory/Makefile deleted file mode 100644 index 45221356cd97..000000000000 --- a/tests/run-make/output-filename-conflicts-with-directory/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -all: - cp foo.rs $(TMPDIR)/foo.rs - mkdir $(TMPDIR)/foo - $(RUSTC) $(TMPDIR)/foo.rs -o $(TMPDIR)/foo 2>&1 \ - | $(CGREP) -e "the generated executable for the input file \".*foo\.rs\" conflicts with the existing directory \".*foo\"" diff --git a/tests/run-make/output-filename-conflicts-with-directory/rmake.rs b/tests/run-make/output-filename-conflicts-with-directory/rmake.rs new file mode 100644 index 000000000000..4b5c9e8d1187 --- /dev/null +++ b/tests/run-make/output-filename-conflicts-with-directory/rmake.rs @@ -0,0 +1,14 @@ +// ignore-tidy-linelength +// When the compiled executable would conflict with a directory, a +// rustc error should be displayed instead of a verbose and +// potentially-confusing linker error. +// See https://github.com/rust-lang/rust/pull/47203 + +use run_make_support::{fs_wrapper, rustc}; + +fn main() { + fs_wrapper::create_dir("foo"); + rustc().input("foo.rs").output("foo").run_fail().assert_stderr_contains( + r#"the generated executable for the input file "foo.rs" conflicts with the existing directory "foo""#, + ); +} diff --git a/tests/run-make/output-filename-overwrites-input/Makefile b/tests/run-make/output-filename-overwrites-input/Makefile deleted file mode 100644 index fe5d231382dc..000000000000 --- a/tests/run-make/output-filename-overwrites-input/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - cp foo.rs $(TMPDIR)/foo - $(RUSTC) $(TMPDIR)/foo -o $(TMPDIR)/foo 2>&1 \ - | $(CGREP) -e "the input file \".*foo\" would be overwritten by the generated executable" - cp bar.rs $(TMPDIR)/bar.rlib - $(RUSTC) $(TMPDIR)/bar.rlib -o $(TMPDIR)/bar.rlib 2>&1 \ - | $(CGREP) -e "the input file \".*bar.rlib\" would be overwritten by the generated executable" - $(RUSTC) foo.rs 2>&1 && $(RUSTC) -Z ls=root $(TMPDIR)/foo 2>&1 - cp foo.rs $(TMPDIR)/foo.rs - $(RUSTC) $(TMPDIR)/foo.rs -o $(TMPDIR)/foo.rs 2>&1 \ - | $(CGREP) -e "the input file \".*foo.rs\" would be overwritten by the generated executable" diff --git a/tests/run-make/output-filename-overwrites-input/rmake.rs b/tests/run-make/output-filename-overwrites-input/rmake.rs new file mode 100644 index 000000000000..c6055e818a17 --- /dev/null +++ b/tests/run-make/output-filename-overwrites-input/rmake.rs @@ -0,0 +1,21 @@ +// If rustc is invoked on a file that would be overwritten by the +// compilation, the compilation should fail, to avoid accidental loss. +// See https://github.com/rust-lang/rust/pull/46814 + +//@ ignore-cross-compile + +use run_make_support::{fs_wrapper, rustc}; + +fn main() { + fs_wrapper::copy("foo.rs", "foo"); + rustc().input("foo").output("foo").run_fail().assert_stderr_contains( + r#"the input file "foo" would be overwritten by the generated executable"#, + ); + fs_wrapper::copy("bar.rs", "bar.rlib"); + rustc().input("bar.rlib").output("bar.rlib").run_fail().assert_stderr_contains( + r#"the input file "bar.rlib" would be overwritten by the generated executable"#, + ); + rustc().input("foo.rs").output("foo.rs").run_fail().assert_stderr_contains( + r#"the input file "foo.rs" would be overwritten by the generated executable"#, + ); +} diff --git a/tests/run-make/separate-link-fail/Makefile b/tests/run-make/separate-link-fail/Makefile deleted file mode 100644 index bfd18fbf972d..000000000000 --- a/tests/run-make/separate-link-fail/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -all: - echo 'fn main(){}' > $(TMPDIR)/main.rs - # Make sure that this fails - ! $(RUSTC) -Z link-only $(TMPDIR)/main.rs 2> $(TMPDIR)/stderr.txt - $(CGREP) "The input does not look like a .rlink file" < $(TMPDIR)/stderr.txt diff --git a/tests/run-make/separate-link-fail/foo.rs b/tests/run-make/separate-link-fail/foo.rs new file mode 100644 index 000000000000..f328e4d9d04c --- /dev/null +++ b/tests/run-make/separate-link-fail/foo.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/run-make/separate-link-fail/rmake.rs b/tests/run-make/separate-link-fail/rmake.rs new file mode 100644 index 000000000000..b5d5300de68f --- /dev/null +++ b/tests/run-make/separate-link-fail/rmake.rs @@ -0,0 +1,15 @@ +// rustc usually wants Rust code as its input. The flag `link-only` is one +// exception, where a .rlink file is instead requested. The compiler should +// fail when the user is wrongly passing the original Rust code +// instead of the generated .rlink file when this flag is on. +// https://github.com/rust-lang/rust/issues/95297 + +use run_make_support::rustc; + +fn main() { + rustc() + .arg("-Zlink-only") + .input("foo.rs") + .run_fail() + .assert_stderr_contains("The input does not look like a .rlink file"); +} diff --git a/tests/run-make/separate-link/Makefile b/tests/run-make/separate-link/Makefile deleted file mode 100644 index d01158d9f5fb..000000000000 --- a/tests/run-make/separate-link/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - echo 'fn main(){}' | $(RUSTC) -Z no-link - - $(RUSTC) -Z link-only $(TMPDIR)/rust_out.rlink - $(call RUN,rust_out) diff --git a/tests/run-make/separate-link/rmake.rs b/tests/run-make/separate-link/rmake.rs new file mode 100644 index 000000000000..e91b25489bc5 --- /dev/null +++ b/tests/run-make/separate-link/rmake.rs @@ -0,0 +1,14 @@ +// The compiler flags no-link (and by extension, link-only) used to be broken +// due to changes in encoding/decoding. This was patched, and this test checks +// that these flags are not broken again, resulting in successful compilation. +// See https://github.com/rust-lang/rust/issues/77857 + +//@ ignore-cross-compile + +use run_make_support::{run, rustc}; + +fn main() { + rustc().stdin(b"fn main(){}").arg("-Zno-link").arg("-").run(); + rustc().arg("-Zlink-only").input("rust_out.rlink").run(); + run("rust_out"); +} diff --git a/tests/run-make/used/Makefile b/tests/run-make/used/Makefile deleted file mode 100644 index e80eb9e40208..000000000000 --- a/tests/run-make/used/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -# ignore-windows-msvc - -all: - $(RUSTC) -C opt-level=3 --emit=obj used.rs - nm $(TMPDIR)/used.o | $(CGREP) FOO diff --git a/tests/run-make/used/rmake.rs b/tests/run-make/used/rmake.rs new file mode 100644 index 000000000000..56ef5c6b9cc0 --- /dev/null +++ b/tests/run-make/used/rmake.rs @@ -0,0 +1,15 @@ +// This test ensures that the compiler is keeping static variables, even if not referenced +// by another part of the program, in the output object file. +// +// It comes from #39987 which implements this RFC for the #[used] attribute: +// https://rust-lang.github.io/rfcs/2386-used.html + +//@ ignore-msvc + +use run_make_support::{cmd, rustc}; + +fn main() { + rustc().opt_level("3").emit("obj").input("used.rs").run(); + + cmd("nm").arg("used.o").run().assert_stdout_contains("FOO"); +} diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.rs b/tests/ui-fulldeps/internal-lints/diagnostics.rs index 7c3a2c97474d..5fcff74064a6 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.rs +++ b/tests/ui-fulldeps/internal-lints/diagnostics.rs @@ -14,8 +14,8 @@ extern crate rustc_session; extern crate rustc_span; use rustc_errors::{ - Diag, DiagCtxt, DiagInner, DiagMessage, Diagnostic, EmissionGuarantee, Level, LintDiagnostic, - SubdiagMessageOp, SubdiagMessage, Subdiagnostic, + Diag, DiagCtxtHandle, DiagInner, DiagMessage, Diagnostic, EmissionGuarantee, Level, + LintDiagnostic, SubdiagMessage, SubdiagMessageOp, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -39,7 +39,7 @@ struct Note { pub struct UntranslatableInDiagnostic; impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UntranslatableInDiagnostic { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { Diag::new(dcx, level, "untranslatable diagnostic") //~^ ERROR diagnostics should be created using translatable messages } @@ -48,7 +48,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UntranslatableInDiagnostic pub struct TranslatableInDiagnostic; impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for TranslatableInDiagnostic { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { Diag::new(dcx, level, crate::fluent_generated::no_crate_example) } } @@ -81,7 +81,7 @@ impl Subdiagnostic for TranslatableInAddtoDiag { pub struct UntranslatableInLintDiagnostic; impl<'a> LintDiagnostic<'a, ()> for UntranslatableInLintDiagnostic { - fn decorate_lint<'b, >(self, diag: &'b mut Diag<'a, ()>) { + fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { diag.note("untranslatable diagnostic"); //~^ ERROR diagnostics should be created using translatable messages } @@ -95,7 +95,7 @@ impl<'a> LintDiagnostic<'a, ()> for TranslatableInLintDiagnostic { } } -pub fn make_diagnostics<'a>(dcx: &'a DiagCtxt) { +pub fn make_diagnostics<'a>(dcx: DiagCtxtHandle<'a>) { let _diag = dcx.struct_err(crate::fluent_generated::no_crate_example); //~^ ERROR diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls @@ -107,7 +107,7 @@ pub fn make_diagnostics<'a>(dcx: &'a DiagCtxt) { // Check that `rustc_lint_diagnostics`-annotated functions aren't themselves linted for // `diagnostic_outside_of_impl`. #[rustc_lint_diagnostics] -pub fn skipped_because_of_annotation<'a>(dcx: &'a DiagCtxt) { +pub fn skipped_because_of_annotation<'a>(dcx: DiagCtxtHandle<'a>) { #[allow(rustc::untranslatable_diagnostic)] let _diag = dcx.struct_err("untranslatable diagnostic"); // okay! } diff --git a/tests/ui/array-slice-vec/vec-res-add.stderr b/tests/ui/array-slice-vec/vec-res-add.stderr index cf5796f7e4a4..34fd69426a8b 100644 --- a/tests/ui/array-slice-vec/vec-res-add.stderr +++ b/tests/ui/array-slice-vec/vec-res-add.stderr @@ -5,6 +5,11 @@ LL | let k = i + j; | - ^ - Vec | | | Vec + | +note: the foreign item type `Vec` doesn't implement `Add` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + | + = note: not implement `Add` error: aborting due to 1 previous error diff --git a/tests/ui/autoderef-full-lval.stderr b/tests/ui/autoderef-full-lval.stderr index 9921ce7c1544..d90238a7fb21 100644 --- a/tests/ui/autoderef-full-lval.stderr +++ b/tests/ui/autoderef-full-lval.stderr @@ -5,6 +5,12 @@ LL | let z: isize = a.x + b.y; | --- ^ --- Box | | | Box + | +note: the foreign item type `Box` doesn't implement `Add` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL + | + = note: not implement `Add` error[E0369]: cannot add `Box` to `Box` --> $DIR/autoderef-full-lval.rs:21:33 @@ -13,6 +19,12 @@ LL | let answer: isize = forty.a + two.a; | ------- ^ ----- Box | | | Box + | +note: the foreign item type `Box` doesn't implement `Add` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL + | + = note: not implement `Add` error: aborting due to 2 previous errors diff --git a/tests/ui/binop/binary-op-not-allowed-issue-125631.rs b/tests/ui/binop/binary-op-not-allowed-issue-125631.rs new file mode 100644 index 000000000000..8827bbb003b1 --- /dev/null +++ b/tests/ui/binop/binary-op-not-allowed-issue-125631.rs @@ -0,0 +1,16 @@ +use std::io::{Error, ErrorKind}; +use std::thread; + +struct T1; +struct T2; + +fn main() { + (Error::new(ErrorKind::Other, "1"), T1, 1) == (Error::new(ErrorKind::Other, "1"), T1, 2); + //~^ERROR binary operation `==` cannot be applied to type + (Error::new(ErrorKind::Other, "2"), thread::current()) + == (Error::new(ErrorKind::Other, "2"), thread::current()); + //~^ERROR binary operation `==` cannot be applied to type + (Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2) + == (Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2); + //~^ERROR binary operation `==` cannot be applied to type +} diff --git a/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr b/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr new file mode 100644 index 000000000000..1cf75bbc1a57 --- /dev/null +++ b/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr @@ -0,0 +1,75 @@ +error[E0369]: binary operation `==` cannot be applied to type `(std::io::Error, T1, {integer})` + --> $DIR/binary-op-not-allowed-issue-125631.rs:8:48 + | +LL | (Error::new(ErrorKind::Other, "1"), T1, 1) == (Error::new(ErrorKind::Other, "1"), T1, 2); + | ------------------------------------------ ^^ ------------------------------------------ (std::io::Error, T1, {integer}) + | | + | (std::io::Error, T1, {integer}) + | +note: an implementation of `PartialEq` might be missing for `T1` + --> $DIR/binary-op-not-allowed-issue-125631.rs:4:1 + | +LL | struct T1; + | ^^^^^^^^^ must implement `PartialEq` +note: the foreign item type `std::io::Error` doesn't implement `PartialEq` + --> $SRC_DIR/std/src/io/error.rs:LL:COL + | + = note: not implement `PartialEq` +help: consider annotating `T1` with `#[derive(PartialEq)]` + | +LL + #[derive(PartialEq)] +LL | struct T1; + | + +error[E0369]: binary operation `==` cannot be applied to type `(std::io::Error, Thread)` + --> $DIR/binary-op-not-allowed-issue-125631.rs:11:9 + | +LL | (Error::new(ErrorKind::Other, "2"), thread::current()) + | ------------------------------------------------------ (std::io::Error, Thread) +LL | == (Error::new(ErrorKind::Other, "2"), thread::current()); + | ^^ ------------------------------------------------------ (std::io::Error, Thread) + | +note: the foreign item types don't implement required traits for this operation to be valid + --> $SRC_DIR/std/src/io/error.rs:LL:COL + | + = note: not implement `PartialEq` + --> $SRC_DIR/std/src/thread/mod.rs:LL:COL + | + = note: not implement `PartialEq` + +error[E0369]: binary operation `==` cannot be applied to type `(std::io::Error, Thread, T1, T2)` + --> $DIR/binary-op-not-allowed-issue-125631.rs:14:9 + | +LL | (Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2) + | -------------------------------------------------------------- (std::io::Error, Thread, T1, T2) +LL | == (Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2); + | ^^ -------------------------------------------------------------- (std::io::Error, Thread, T1, T2) + | +note: the following types would have to `impl` their required traits for this operation to be valid + --> $DIR/binary-op-not-allowed-issue-125631.rs:4:1 + | +LL | struct T1; + | ^^^^^^^^^ must implement `PartialEq` +LL | struct T2; + | ^^^^^^^^^ must implement `PartialEq` +note: the foreign item types don't implement required traits for this operation to be valid + --> $SRC_DIR/std/src/io/error.rs:LL:COL + | + = note: not implement `PartialEq` + --> $SRC_DIR/std/src/thread/mod.rs:LL:COL + | + = note: not implement `PartialEq` +help: consider annotating `T1` with `#[derive(PartialEq)]` + | +LL + #[derive(PartialEq)] +LL | struct T1; + | +help: consider annotating `T2` with `#[derive(PartialEq)]` + | +LL + #[derive(PartialEq)] +LL | struct T2; + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/binop/binop-bitxor-str.stderr b/tests/ui/binop/binop-bitxor-str.stderr index 20b1ecc5a939..9d9ec6c5af6b 100644 --- a/tests/ui/binop/binop-bitxor-str.stderr +++ b/tests/ui/binop/binop-bitxor-str.stderr @@ -5,6 +5,11 @@ LL | fn main() { let x = "a".to_string() ^ "b".to_string(); } | --------------- ^ --------------- String | | | String + | +note: the foreign item type `String` doesn't implement `BitXor` + --> $SRC_DIR/alloc/src/string.rs:LL:COL + | + = note: not implement `BitXor` error: aborting due to 1 previous error diff --git a/tests/ui/coverage-attr/bad-syntax.rs b/tests/ui/coverage-attr/bad-syntax.rs new file mode 100644 index 000000000000..8783714992b7 --- /dev/null +++ b/tests/ui/coverage-attr/bad-syntax.rs @@ -0,0 +1,58 @@ +#![feature(coverage_attribute)] + +// Tests the error messages produced (or not produced) by various unusual +// uses of the `#[coverage(..)]` attribute. + +// FIXME(#84605): Multiple coverage attributes with the same value are useless, +// and should probably produce a diagnostic. +#[coverage(off)] +#[coverage(off)] +fn multiple_consistent() {} + +// FIXME(#84605): When there are multiple inconsistent coverage attributes, +// it's unclear which one will prevail. +#[coverage(off)] +#[coverage(on)] +fn multiple_inconsistent() {} + +#[coverage] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn bare_word() {} + +// FIXME(#84605): This shows as multiple different errors, one of which suggests +// writing bare `#[coverage]`, which is not allowed. +#[coverage = true] +//~^ ERROR expected `coverage(off)` or `coverage(on)` +//~| ERROR malformed `coverage` attribute input +//~| HELP the following are the possible correct uses +//~| SUGGESTION #[coverage(on|off)] +fn key_value() {} + +#[coverage()] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn list_empty() {} + +#[coverage(off, off)] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn list_consistent() {} + +#[coverage(off, on)] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn list_inconsistent() {} + +#[coverage(bogus)] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn bogus_word() {} + +#[coverage(bogus, off)] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn bogus_word_before() {} + +#[coverage(off, bogus)] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn bogus_word_after() {} + +#[coverage(off,)] +fn comma_after() {} + +// FIXME(#84605): This shows as multiple different errors. +#[coverage(,off)] +//~^ ERROR expected identifier, found `,` +//~| HELP remove this comma +//~| ERROR expected `coverage(off)` or `coverage(on)` +fn comma_before() {} + +fn main() {} diff --git a/tests/ui/coverage-attr/bad-syntax.stderr b/tests/ui/coverage-attr/bad-syntax.stderr new file mode 100644 index 000000000000..f6181d12a946 --- /dev/null +++ b/tests/ui/coverage-attr/bad-syntax.stderr @@ -0,0 +1,78 @@ +error: malformed `coverage` attribute input + --> $DIR/bad-syntax.rs:23:1 + | +LL | #[coverage = true] + | ^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[coverage(on|off)] + | +LL | #[coverage] + | + +error: expected identifier, found `,` + --> $DIR/bad-syntax.rs:52:12 + | +LL | #[coverage(,off)] + | ^ + | | + | expected identifier + | help: remove this comma + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:18:1 + | +LL | #[coverage] + | ^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:23:1 + | +LL | #[coverage = true] + | ^^^^^^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:30:1 + | +LL | #[coverage()] + | ^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:33:1 + | +LL | #[coverage(off, off)] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:36:1 + | +LL | #[coverage(off, on)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:39:1 + | +LL | #[coverage(bogus)] + | ^^^^^^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:42:1 + | +LL | #[coverage(bogus, off)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:45:1 + | +LL | #[coverage(off, bogus)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:52:1 + | +LL | #[coverage(,off)] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 11 previous errors + diff --git a/tests/ui/lint/no-coverage.rs b/tests/ui/coverage-attr/no-coverage.rs similarity index 100% rename from tests/ui/lint/no-coverage.rs rename to tests/ui/coverage-attr/no-coverage.rs diff --git a/tests/ui/lint/no-coverage.stderr b/tests/ui/coverage-attr/no-coverage.stderr similarity index 100% rename from tests/ui/lint/no-coverage.stderr rename to tests/ui/coverage-attr/no-coverage.stderr diff --git a/tests/ui/error-codes/E0067.stderr b/tests/ui/error-codes/E0067.stderr index ec0358cb7dfe..71b720805442 100644 --- a/tests/ui/error-codes/E0067.stderr +++ b/tests/ui/error-codes/E0067.stderr @@ -5,6 +5,12 @@ LL | LinkedList::new() += 1; | -----------------^^^^^ | | | cannot use `+=` on type `LinkedList<_>` + | +note: the foreign item type `LinkedList<_>` doesn't implement `AddAssign<{integer}>` + --> $SRC_DIR/alloc/src/collections/linked_list.rs:LL:COL + ::: $SRC_DIR/alloc/src/collections/linked_list.rs:LL:COL + | + = note: not implement `AddAssign<{integer}>` error[E0067]: invalid left-hand side of assignment --> $DIR/E0067.rs:4:23 diff --git a/tests/ui/feature-gates/feature-gate-precise-capturing.rs b/tests/ui/feature-gates/feature-gate-precise-capturing.rs index 0c3b49776230..47a21539d377 100644 --- a/tests/ui/feature-gates/feature-gate-precise-capturing.rs +++ b/tests/ui/feature-gates/feature-gate-precise-capturing.rs @@ -1,4 +1,4 @@ -fn hello() -> impl use<> Sized {} +fn hello() -> impl Sized + use<> {} //~^ ERROR precise captures on `impl Trait` are experimental fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-precise-capturing.stderr b/tests/ui/feature-gates/feature-gate-precise-capturing.stderr index 102b39148f9f..04365408880d 100644 --- a/tests/ui/feature-gates/feature-gate-precise-capturing.stderr +++ b/tests/ui/feature-gates/feature-gate-precise-capturing.stderr @@ -1,8 +1,8 @@ error[E0658]: precise captures on `impl Trait` are experimental - --> $DIR/feature-gate-precise-capturing.rs:1:20 + --> $DIR/feature-gate-precise-capturing.rs:1:28 | -LL | fn hello() -> impl use<> Sized {} - | ^^^ +LL | fn hello() -> impl Sized + use<> {} + | ^^^ | = note: see issue #123432 for more information = help: add `#![feature(precise_capturing)]` to the crate attributes to enable diff --git a/tests/ui/impl-trait/call_method_ambiguous.next.stderr b/tests/ui/impl-trait/call_method_ambiguous.next.stderr index cd222aa7ae9f..a1f9a8b40a89 100644 --- a/tests/ui/impl-trait/call_method_ambiguous.next.stderr +++ b/tests/ui/impl-trait/call_method_ambiguous.next.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/call_method_ambiguous.rs:29:13 + --> $DIR/call_method_ambiguous.rs:28:13 | LL | let mut iter = foo(n - 1, m); | ^^^^^^^^ diff --git a/tests/ui/impl-trait/call_method_ambiguous.rs b/tests/ui/impl-trait/call_method_ambiguous.rs index c26c01e002d8..4dac605d6b81 100644 --- a/tests/ui/impl-trait/call_method_ambiguous.rs +++ b/tests/ui/impl-trait/call_method_ambiguous.rs @@ -3,7 +3,6 @@ //@[current] run-pass #![feature(precise_capturing)] -#![allow(incomplete_features)] trait Get { fn get(&mut self) -> u32; @@ -24,7 +23,7 @@ where } } -fn foo(n: usize, m: &mut ()) -> impl use<'_> Get { +fn foo(n: usize, m: &mut ()) -> impl Get + use<'_> { if n > 0 { let mut iter = foo(n - 1, m); //[next]~^ type annotations needed diff --git a/tests/ui/impl-trait/precise-capturing/apit.rs b/tests/ui/impl-trait/precise-capturing/apit.rs index efcac9ebb0b8..64c15d6df96c 100644 --- a/tests/ui/impl-trait/precise-capturing/apit.rs +++ b/tests/ui/impl-trait/precise-capturing/apit.rs @@ -1,7 +1,6 @@ #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn hello(_: impl use<> Sized) {} -//~^ ERROR `use<...>` precise capturing syntax not allowed on argument-position `impl Trait` +fn hello(_: impl Sized + use<>) {} +//~^ ERROR `use<...>` precise capturing syntax not allowed in argument-position `impl Trait` fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/apit.stderr b/tests/ui/impl-trait/precise-capturing/apit.stderr index 96548f5732f5..1d6225a1ff8d 100644 --- a/tests/ui/impl-trait/precise-capturing/apit.stderr +++ b/tests/ui/impl-trait/precise-capturing/apit.stderr @@ -1,17 +1,8 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/apit.rs:1:12 +error: `use<...>` precise capturing syntax not allowed in argument-position `impl Trait` + --> $DIR/apit.rs:3:26 | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 for more information - = note: `#[warn(incomplete_features)]` on by default +LL | fn hello(_: impl Sized + use<>) {} + | ^^^^^ -error: `use<...>` precise capturing syntax not allowed on argument-position `impl Trait` - --> $DIR/apit.rs:4:18 - | -LL | fn hello(_: impl use<> Sized) {} - | ^^^^^ - -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs index 623063a8f502..d2d4570c570e 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs +++ b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs @@ -1,14 +1,13 @@ #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn no_elided_lt() -> impl use<'_> Sized {} +fn no_elided_lt() -> impl Sized + use<'_> {} //~^ ERROR missing lifetime specifier //~| ERROR expected lifetime parameter in `use<...>` precise captures list, found `'_` -fn static_lt() -> impl use<'static> Sized {} +fn static_lt() -> impl Sized + use<'static> {} //~^ ERROR expected lifetime parameter in `use<...>` precise captures list, found `'static` -fn missing_lt() -> impl use<'missing> Sized {} +fn missing_lt() -> impl Sized + use<'missing> {} //~^ ERROR use of undeclared lifetime name `'missing` fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr index a926362c50c8..550996ab5e57 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr +++ b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr @@ -1,45 +1,36 @@ error[E0106]: missing lifetime specifier - --> $DIR/bad-lifetimes.rs:4:31 + --> $DIR/bad-lifetimes.rs:3:39 | -LL | fn no_elided_lt() -> impl use<'_> Sized {} - | ^^ expected named lifetime parameter +LL | fn no_elided_lt() -> impl Sized + use<'_> {} + | ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values | -LL | fn no_elided_lt() -> impl use<'static> Sized {} - | ~~~~~~~ +LL | fn no_elided_lt() -> impl Sized + use<'static> {} + | ~~~~~~~ error[E0261]: use of undeclared lifetime name `'missing` - --> $DIR/bad-lifetimes.rs:11:29 + --> $DIR/bad-lifetimes.rs:10:37 | -LL | fn missing_lt() -> impl use<'missing> Sized {} - | - ^^^^^^^^ undeclared lifetime +LL | fn missing_lt() -> impl Sized + use<'missing> {} + | - ^^^^^^^^ undeclared lifetime | | | help: consider introducing lifetime `'missing` here: `<'missing>` -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/bad-lifetimes.rs:1:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 for more information - = note: `#[warn(incomplete_features)]` on by default - error: expected lifetime parameter in `use<...>` precise captures list, found `'_` - --> $DIR/bad-lifetimes.rs:4:31 + --> $DIR/bad-lifetimes.rs:3:39 | -LL | fn no_elided_lt() -> impl use<'_> Sized {} - | ^^ +LL | fn no_elided_lt() -> impl Sized + use<'_> {} + | ^^ error: expected lifetime parameter in `use<...>` precise captures list, found `'static` - --> $DIR/bad-lifetimes.rs:8:28 + --> $DIR/bad-lifetimes.rs:7:36 | -LL | fn static_lt() -> impl use<'static> Sized {} - | ^^^^^^^ +LL | fn static_lt() -> impl Sized + use<'static> {} + | ^^^^^^^ -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors Some errors have detailed explanations: E0106, E0261. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.rs b/tests/ui/impl-trait/precise-capturing/bad-params.rs index 7970d49bf7c0..08eee67c0e57 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-params.rs +++ b/tests/ui/impl-trait/precise-capturing/bad-params.rs @@ -1,19 +1,18 @@ #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn missing() -> impl use Sized {} +fn missing() -> impl Sized + use {} //~^ ERROR cannot find type `T` in this scope -fn missing_self() -> impl use Sized {} +fn missing_self() -> impl Sized + use {} //~^ ERROR cannot find type `Self` in this scope struct MyType; impl MyType { - fn self_is_not_param() -> impl use Sized {} + fn self_is_not_param() -> impl Sized + use {} //~^ ERROR `Self` can't be captured in `use<...>` precise captures list, since it is an alias } -fn hello() -> impl use Sized {} +fn hello() -> impl Sized + use {} //~^ ERROR expected type or const parameter in `use<...>` precise captures list, found function fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.stderr b/tests/ui/impl-trait/precise-capturing/bad-params.stderr index 27bf05302f9b..e104f115aa3f 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-params.stderr +++ b/tests/ui/impl-trait/precise-capturing/bad-params.stderr @@ -1,46 +1,37 @@ error[E0412]: cannot find type `T` in this scope - --> $DIR/bad-params.rs:4:26 + --> $DIR/bad-params.rs:3:34 | -LL | fn missing() -> impl use Sized {} - | ^ not found in this scope +LL | fn missing() -> impl Sized + use {} + | ^ not found in this scope | help: you might be missing a type parameter | -LL | fn missing() -> impl use Sized {} +LL | fn missing() -> impl Sized + use {} | +++ error[E0411]: cannot find type `Self` in this scope - --> $DIR/bad-params.rs:7:31 + --> $DIR/bad-params.rs:6:39 | -LL | fn missing_self() -> impl use Sized {} - | ------------ ^^^^ `Self` is only available in impls, traits, and type definitions +LL | fn missing_self() -> impl Sized + use {} + | ------------ ^^^^ `Self` is only available in impls, traits, and type definitions | | | `Self` not allowed in a function -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/bad-params.rs:1:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 for more information - = note: `#[warn(incomplete_features)]` on by default - error: `Self` can't be captured in `use<...>` precise captures list, since it is an alias - --> $DIR/bad-params.rs:12:40 + --> $DIR/bad-params.rs:11:48 | LL | impl MyType { | ----------- `Self` is not a generic argument, but an alias to the type of the implementation -LL | fn self_is_not_param() -> impl use Sized {} - | ^^^^ +LL | fn self_is_not_param() -> impl Sized + use {} + | ^^^^ error: expected type or const parameter in `use<...>` precise captures list, found function - --> $DIR/bad-params.rs:16:24 + --> $DIR/bad-params.rs:15:32 | -LL | fn hello() -> impl use Sized {} - | ^^^^^ +LL | fn hello() -> impl Sized + use {} + | ^^^^^ -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors Some errors have detailed explanations: E0411, E0412. For more information about an error, try `rustc --explain E0411`. diff --git a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs index 35b28d0e6fb5..82b953bfed4b 100644 --- a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs +++ b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs @@ -1,5 +1,4 @@ #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete trait Tr { type Assoc; @@ -13,25 +12,25 @@ impl Tr for W<'_> { // The normal way of capturing `'a`... impl<'a> W<'a> { - fn good1() -> impl use<'a> Into< as Tr>::Assoc> {} + fn good1() -> impl Into< as Tr>::Assoc> + use<'a> {} } // This ensures that we don't error when we capture the *parent* copy of `'a`, // since the opaque captures that rather than the duplicated `'a` lifetime // synthesized from mentioning `'a` directly in the bounds. impl<'a> W<'a> { - fn good2() -> impl use<'a> Into<::Assoc> {} + fn good2() -> impl Into<::Assoc> + use<'a> {} } // The normal way of capturing `'a`... but not mentioned in the bounds. impl<'a> W<'a> { - fn bad1() -> impl use<> Into< as Tr>::Assoc> {} + fn bad1() -> impl Into< as Tr>::Assoc> + use<> {} //~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list } // But also make sure that we error here... impl<'a> W<'a> { - fn bad2() -> impl use<> Into<::Assoc> {} + fn bad2() -> impl Into<::Assoc> + use<> {} //~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list } diff --git a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr index 13aaa9997073..b521ee0a9023 100644 --- a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr +++ b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr @@ -1,27 +1,18 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/capture-parent-arg.rs:1:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 for more information - = note: `#[warn(incomplete_features)]` on by default - error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list - --> $DIR/capture-parent-arg.rs:28:37 + --> $DIR/capture-parent-arg.rs:27:31 | LL | impl<'a> W<'a> { | -- this lifetime parameter is captured -LL | fn bad1() -> impl use<> Into< as Tr>::Assoc> {} - | -------------------^^---------------- lifetime captured due to being mentioned in the bounds of the `impl Trait` +LL | fn bad1() -> impl Into< as Tr>::Assoc> + use<> {} + | -------------^^------------------------ lifetime captured due to being mentioned in the bounds of the `impl Trait` error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list - --> $DIR/capture-parent-arg.rs:34:18 + --> $DIR/capture-parent-arg.rs:33:18 | LL | impl<'a> W<'a> { | -- this lifetime parameter is captured -LL | fn bad2() -> impl use<> Into<::Assoc> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime captured due to being mentioned in the bounds of the `impl Trait` +LL | fn bad2() -> impl Into<::Assoc> + use<> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime captured due to being mentioned in the bounds of the `impl Trait` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr b/tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr new file mode 100644 index 000000000000..d8edd672b48c --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr @@ -0,0 +1,8 @@ +error: duplicate `use<...>` precise capturing syntax + --> $DIR/duplicated-use.rs:7:32 + | +LL | fn hello<'a>() -> impl Sized + use<'a> + use<'a> {} + | ^^^^^^^ ------- second `use<...>` here + +error: aborting due to 1 previous error + diff --git a/tests/ui/impl-trait/precise-capturing/duplicated-use.rs b/tests/ui/impl-trait/precise-capturing/duplicated-use.rs new file mode 100644 index 000000000000..bfbdcdbf311d --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/duplicated-use.rs @@ -0,0 +1,10 @@ +//@ revisions: real pre_expansion +//@[pre_expansion] check-pass + +#![feature(precise_capturing)] + +#[cfg(real)] +fn hello<'a>() -> impl Sized + use<'a> + use<'a> {} +//[real]~^ ERROR duplicate `use<...>` precise capturing syntax + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/dyn-use.rs b/tests/ui/impl-trait/precise-capturing/dyn-use.rs new file mode 100644 index 000000000000..ce7a0f3c7b21 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/dyn-use.rs @@ -0,0 +1,4 @@ +#![feature(precise_capturing)] + +fn dyn() -> &'static dyn use<> { &() } +//~^ ERROR expected one of `!`, `(`, `::`, `<`, `where`, or `{`, found keyword `use` diff --git a/tests/ui/impl-trait/precise-capturing/dyn-use.stderr b/tests/ui/impl-trait/precise-capturing/dyn-use.stderr new file mode 100644 index 000000000000..5519633de1f7 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/dyn-use.stderr @@ -0,0 +1,8 @@ +error: expected one of `!`, `(`, `::`, `<`, `where`, or `{`, found keyword `use` + --> $DIR/dyn-use.rs:3:26 + | +LL | fn dyn() -> &'static dyn use<> { &() } + | ^^^ expected one of `!`, `(`, `::`, `<`, `where`, or `{` + +error: aborting due to 1 previous error + diff --git a/tests/ui/impl-trait/precise-capturing/elided.rs b/tests/ui/impl-trait/precise-capturing/elided.rs index de80e8a5d581..34d1ba620dce 100644 --- a/tests/ui/impl-trait/precise-capturing/elided.rs +++ b/tests/ui/impl-trait/precise-capturing/elided.rs @@ -1,8 +1,7 @@ //@ check-pass #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn elided(x: &()) -> impl use<'_> Sized { x } +fn elided(x: &()) -> impl Sized + use<'_> { x } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/elided.stderr b/tests/ui/impl-trait/precise-capturing/elided.stderr deleted file mode 100644 index 38da0828de97..000000000000 --- a/tests/ui/impl-trait/precise-capturing/elided.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/elided.rs:3:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs index 1b604e6c358b..26d29e456eaa 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs @@ -1,7 +1,6 @@ #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn constant() -> impl use<> Sized {} +fn constant() -> impl Sized + use<> {} //~^ ERROR `impl Trait` must mention all const parameters in scope fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr index 3f78e7c56b6e..989ed136d4c3 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr @@ -1,21 +1,12 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/forgot-to-capture-const.rs:1:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 for more information - = note: `#[warn(incomplete_features)]` on by default - error: `impl Trait` must mention all const parameters in scope in `use<...>` - --> $DIR/forgot-to-capture-const.rs:4:34 + --> $DIR/forgot-to-capture-const.rs:3:34 | -LL | fn constant() -> impl use<> Sized {} - | -------------- ^^^^^^^^^^^^^^^^ +LL | fn constant() -> impl Sized + use<> {} + | -------------- ^^^^^^^^^^^^^^^^^^ | | | const parameter is implicitly captured by this `impl Trait` | = note: currently, all const parameters are required to be mentioned in the precise captures list -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs index cc86bf83107e..f18dbca6c5ef 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs @@ -1,10 +1,9 @@ #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn lifetime_in_bounds<'a>(x: &'a ()) -> impl use<> Into<&'a ()> { x } +fn lifetime_in_bounds<'a>(x: &'a ()) -> impl Into<&'a ()> + use<> { x } //~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list -fn lifetime_in_hidden<'a>(x: &'a ()) -> impl use<> Sized { x } +fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> { x } //~^ ERROR hidden type for `impl Sized` captures lifetime that does not appear in bounds fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr index e472c898050a..6544837ba832 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr @@ -1,35 +1,26 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/forgot-to-capture-lifetime.rs:1:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 for more information - = note: `#[warn(incomplete_features)]` on by default - error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list - --> $DIR/forgot-to-capture-lifetime.rs:4:58 + --> $DIR/forgot-to-capture-lifetime.rs:3:52 | -LL | fn lifetime_in_bounds<'a>(x: &'a ()) -> impl use<> Into<&'a ()> { x } - | -- -----------------^^---- +LL | fn lifetime_in_bounds<'a>(x: &'a ()) -> impl Into<&'a ()> + use<> { x } + | -- -----------^^------------ | | | | | lifetime captured due to being mentioned in the bounds of the `impl Trait` | this lifetime parameter is captured error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds - --> $DIR/forgot-to-capture-lifetime.rs:7:60 + --> $DIR/forgot-to-capture-lifetime.rs:6:62 | -LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl use<> Sized { x } - | -- ---------------- ^ +LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> { x } + | -- ------------------ ^ | | | | | opaque type defined here | hidden type `&'a ()` captures the lifetime `'a` as defined here | help: to declare that `impl Sized` captures `'a`, you can add an explicit `'a` lifetime bound | -LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl use<> Sized + 'a { x } - | ++++ +LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> + 'a { x } + | ++++ -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs index d359ea5e26df..080149857839 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs @@ -1,11 +1,10 @@ #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn type_param() -> impl use<> Sized {} +fn type_param() -> impl Sized + use<> {} //~^ ERROR `impl Trait` must mention all type parameters in scope trait Foo { - fn bar() -> impl use<> Sized; + fn bar() -> impl Sized + use<>; //~^ ERROR `impl Trait` must mention the `Self` type of the trait } diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr index 26994d0bdbf1..93b44a0c18c2 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr @@ -1,31 +1,22 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/forgot-to-capture-type.rs:1:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 for more information - = note: `#[warn(incomplete_features)]` on by default - error: `impl Trait` must mention all type parameters in scope in `use<...>` - --> $DIR/forgot-to-capture-type.rs:4:23 + --> $DIR/forgot-to-capture-type.rs:3:23 | -LL | fn type_param() -> impl use<> Sized {} - | - ^^^^^^^^^^^^^^^^ +LL | fn type_param() -> impl Sized + use<> {} + | - ^^^^^^^^^^^^^^^^^^ | | | type parameter is implicitly captured by this `impl Trait` | = note: currently, all type parameters are required to be mentioned in the precise captures list error: `impl Trait` must mention the `Self` type of the trait in `use<...>` - --> $DIR/forgot-to-capture-type.rs:8:17 + --> $DIR/forgot-to-capture-type.rs:7:17 | LL | trait Foo { | --------- `Self` type parameter is implicitly captured by this `impl Trait` -LL | fn bar() -> impl use<> Sized; - | ^^^^^^^^^^^^^^^^ +LL | fn bar() -> impl Sized + use<>; + | ^^^^^^^^^^^^^^^^^^ | = note: currently, all type parameters are required to be mentioned in the precise captures list -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/higher-ranked.rs b/tests/ui/impl-trait/precise-capturing/higher-ranked.rs index 28fb1fa4b9ec..21ac19640bcd 100644 --- a/tests/ui/impl-trait/precise-capturing/higher-ranked.rs +++ b/tests/ui/impl-trait/precise-capturing/higher-ranked.rs @@ -3,7 +3,6 @@ // Show how precise captures allow us to skip capturing a higher-ranked lifetime #![feature(lifetime_capture_rules_2024, precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete trait Trait<'a> { type Item; @@ -13,6 +12,6 @@ impl Trait<'_> for () { type Item = Vec<()>; } -fn hello() -> impl for<'a> Trait<'a, Item = impl use<> IntoIterator> {} +fn hello() -> impl for<'a> Trait<'a, Item = impl IntoIterator + use<>> {} fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/higher-ranked.stderr b/tests/ui/impl-trait/precise-capturing/higher-ranked.stderr deleted file mode 100644 index e48d6d42af07..000000000000 --- a/tests/ui/impl-trait/precise-capturing/higher-ranked.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/higher-ranked.rs:5:41 - | -LL | #![feature(lifetime_capture_rules_2024, precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/impl-trait/precise-capturing/illegal-positions.real.stderr b/tests/ui/impl-trait/precise-capturing/illegal-positions.real.stderr new file mode 100644 index 000000000000..2b234bcb6a50 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/illegal-positions.real.stderr @@ -0,0 +1,57 @@ +error: `use<...>` precise capturing syntax not allowed in supertrait bounds + --> $DIR/illegal-positions.rs:8:12 + | +LL | trait Foo: use<> { + | ^^^^^ + +error: `use<...>` precise capturing syntax not allowed in bounds + --> $DIR/illegal-positions.rs:10:33 + | +LL | type Assoc: use<> where (): use<>; + | ^^^^^ + +error: `use<...>` precise capturing syntax not allowed in bounds + --> $DIR/illegal-positions.rs:10:17 + | +LL | type Assoc: use<> where (): use<>; + | ^^^^^ + +error: `use<...>` precise capturing syntax not allowed in bounds + --> $DIR/illegal-positions.rs:16:11 + | +LL | fn fun>(_: impl use<>) where (): use<> {} + | ^^^^^ + +error: `use<...>` precise capturing syntax not allowed in bounds + --> $DIR/illegal-positions.rs:16:43 + | +LL | fn fun>(_: impl use<>) where (): use<> {} + | ^^^^^ + +error: at least one trait must be specified + --> $DIR/illegal-positions.rs:16:21 + | +LL | fn fun>(_: impl use<>) where (): use<> {} + | ^^^^^^^^^^ + +error: `use<...>` precise capturing syntax not allowed in `dyn` trait object bounds + --> $DIR/illegal-positions.rs:23:25 + | +LL | fn dynamic() -> Box> {} + | ^^^^^ + +error: `use<...>` precise capturing syntax not allowed in argument-position `impl Trait` + --> $DIR/illegal-positions.rs:16:26 + | +LL | fn fun>(_: impl use<>) where (): use<> {} + | ^^^^^ + +error[E0224]: at least one trait is required for an object type + --> $DIR/illegal-positions.rs:23:21 + | +LL | fn dynamic() -> Box> {} + | ^^^^^^^^^ + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0224`. diff --git a/tests/ui/impl-trait/precise-capturing/illegal-positions.rs b/tests/ui/impl-trait/precise-capturing/illegal-positions.rs new file mode 100644 index 000000000000..681458e25f80 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/illegal-positions.rs @@ -0,0 +1,27 @@ +//@ revisions: real pre_expansion +//@[pre_expansion] check-pass +//@ edition: 2021 + +#![feature(precise_capturing)] + +#[cfg(real)] +trait Foo: use<> { + //[real]~^ ERROR `use<...>` precise capturing syntax not allowed + type Assoc: use<> where (): use<>; + //[real]~^ ERROR `use<...>` precise capturing syntax not allowed + //[real]~| ERROR `use<...>` precise capturing syntax not allowed +} + +#[cfg(real)] +fn fun>(_: impl use<>) where (): use<> {} +//[real]~^ ERROR `use<...>` precise capturing syntax not allowed +//[real]~| ERROR `use<...>` precise capturing syntax not allowed +//[real]~| ERROR `use<...>` precise capturing syntax not allowed +//[real]~| ERROR at least one trait must be specified + +#[cfg(real)] +fn dynamic() -> Box> {} +//[real]~^ ERROR `use<...>` precise capturing syntax not allowed in `dyn` trait object bounds +//[real]~| ERROR at least one trait is required for an object type [E0224] + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/ordering.rs b/tests/ui/impl-trait/precise-capturing/ordering.rs index 2bace798c570..eb570a120cc4 100644 --- a/tests/ui/impl-trait/precise-capturing/ordering.rs +++ b/tests/ui/impl-trait/precise-capturing/ordering.rs @@ -1,16 +1,15 @@ #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn lt<'a>() -> impl use<'a, 'a> Sized {} +fn lt<'a>() -> impl Sized + use<'a, 'a> {} //~^ ERROR cannot capture parameter `'a` twice -fn ty() -> impl use Sized {} +fn ty() -> impl Sized + use {} //~^ ERROR cannot capture parameter `T` twice -fn ct() -> impl use Sized {} +fn ct() -> impl Sized + use {} //~^ ERROR cannot capture parameter `N` twice -fn ordering<'a, T>() -> impl use Sized {} +fn ordering<'a, T>() -> impl Sized + use {} //~^ ERROR lifetime parameter `'a` must be listed before non-lifetime parameters fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/ordering.stderr b/tests/ui/impl-trait/precise-capturing/ordering.stderr index 3f545108df56..ecd47159059b 100644 --- a/tests/ui/impl-trait/precise-capturing/ordering.stderr +++ b/tests/ui/impl-trait/precise-capturing/ordering.stderr @@ -1,37 +1,28 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/ordering.rs:1:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 for more information - = note: `#[warn(incomplete_features)]` on by default - error: cannot capture parameter `'a` twice - --> $DIR/ordering.rs:4:25 + --> $DIR/ordering.rs:3:33 | -LL | fn lt<'a>() -> impl use<'a, 'a> Sized {} - | ^^ -- parameter captured again here +LL | fn lt<'a>() -> impl Sized + use<'a, 'a> {} + | ^^ -- parameter captured again here error: cannot capture parameter `T` twice - --> $DIR/ordering.rs:7:24 + --> $DIR/ordering.rs:6:32 | -LL | fn ty() -> impl use Sized {} - | ^ - parameter captured again here +LL | fn ty() -> impl Sized + use {} + | ^ - parameter captured again here error: cannot capture parameter `N` twice - --> $DIR/ordering.rs:10:37 + --> $DIR/ordering.rs:9:45 | -LL | fn ct() -> impl use Sized {} - | ^ - parameter captured again here +LL | fn ct() -> impl Sized + use {} + | ^ - parameter captured again here error: lifetime parameter `'a` must be listed before non-lifetime parameters - --> $DIR/ordering.rs:13:37 + --> $DIR/ordering.rs:12:45 | -LL | fn ordering<'a, T>() -> impl use Sized {} - | - ^^ - | | - | move the lifetime before this parameter +LL | fn ordering<'a, T>() -> impl Sized + use {} + | - ^^ + | | + | move the lifetime before this parameter -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/outlives.rs b/tests/ui/impl-trait/precise-capturing/outlives.rs index 71e6333934e7..26ac922b5b9d 100644 --- a/tests/ui/impl-trait/precise-capturing/outlives.rs +++ b/tests/ui/impl-trait/precise-capturing/outlives.rs @@ -3,9 +3,8 @@ // Show that precise captures allow us to skip a lifetime param for outlives #![feature(lifetime_capture_rules_2024, precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn hello<'a: 'a, 'b: 'b>() -> impl use<'a> Sized { } +fn hello<'a: 'a, 'b: 'b>() -> impl Sized + use<'a> { } fn outlives<'a, T: 'a>(_: T) {} diff --git a/tests/ui/impl-trait/precise-capturing/outlives.stderr b/tests/ui/impl-trait/precise-capturing/outlives.stderr deleted file mode 100644 index 405c09cccd94..000000000000 --- a/tests/ui/impl-trait/precise-capturing/outlives.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/outlives.rs:5:41 - | -LL | #![feature(lifetime_capture_rules_2024, precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed index 014ab23e4ebc..5ac296a9cbdf 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed @@ -4,15 +4,15 @@ #![allow(unused, incomplete_features)] #![deny(impl_trait_overcaptures)] -fn named<'a>(x: &'a i32) -> impl use<> Sized { *x } +fn named<'a>(x: &'a i32) -> impl Sized + use<> { *x } //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 -fn implicit(x: &i32) -> impl use<> Sized { *x } +fn implicit(x: &i32) -> impl Sized + use<> { *x } //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 struct W; impl W { - fn hello(&self, x: &i32) -> impl use<'_> Sized + '_ { self } + fn hello(&self, x: &i32) -> impl Sized + '_ + use<'_> { self } //~^ ERROR `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024 } @@ -23,7 +23,7 @@ impl Higher<'_> for () { type Output = (); } -fn hrtb() -> impl for<'a> Higher<'a, Output = impl use<> Sized> {} +fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {} //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr index 16cb8b7e94b1..f8bb7f099af9 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr @@ -17,8 +17,8 @@ LL | #![deny(impl_trait_overcaptures)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the precise capturing `use<...>` syntax to make the captures explicit | -LL | fn named<'a>(x: &'a i32) -> impl use<> Sized { *x } - | +++++ +LL | fn named<'a>(x: &'a i32) -> impl Sized + use<> { *x } + | +++++++ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 --> $DIR/overcaptures-2024.rs:10:25 @@ -34,8 +34,8 @@ LL | fn implicit(x: &i32) -> impl Sized { *x } = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 help: use the precise capturing `use<...>` syntax to make the captures explicit | -LL | fn implicit(x: &i32) -> impl use<> Sized { *x } - | +++++ +LL | fn implicit(x: &i32) -> impl Sized + use<> { *x } + | +++++++ error: `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024 --> $DIR/overcaptures-2024.rs:15:33 @@ -51,8 +51,8 @@ LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self } = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 help: use the precise capturing `use<...>` syntax to make the captures explicit | -LL | fn hello(&self, x: &i32) -> impl use<'_> Sized + '_ { self } - | +++++++ +LL | fn hello(&self, x: &i32) -> impl Sized + '_ + use<'_> { self } + | +++++++++ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 --> $DIR/overcaptures-2024.rs:26:47 @@ -68,8 +68,8 @@ LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {} = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 help: use the precise capturing `use<...>` syntax to make the captures explicit | -LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl use<> Sized> {} - | +++++ +LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {} + | +++++++ error: aborting due to 4 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rs b/tests/ui/impl-trait/precise-capturing/redundant.rs index 108a4cb64aa8..99c128fdc482 100644 --- a/tests/ui/impl-trait/precise-capturing/redundant.rs +++ b/tests/ui/impl-trait/precise-capturing/redundant.rs @@ -2,23 +2,22 @@ //@ check-pass #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn hello<'a>() -> impl use<'a> Sized {} +fn hello<'a>() -> impl Sized + use<'a> {} //~^ WARN all possible in-scope parameters are already captured struct Inherent; impl Inherent { - fn inherent(&self) -> impl use<'_> Sized {} + fn inherent(&self) -> impl Sized + use<'_> {} //~^ WARN all possible in-scope parameters are already captured } trait Test<'a> { - fn in_trait() -> impl use<'a, Self> Sized; + fn in_trait() -> impl Sized + use<'a, Self>; //~^ WARN all possible in-scope parameters are already captured } impl<'a> Test<'a> for () { - fn in_trait() -> impl use<'a> Sized {} + fn in_trait() -> impl Sized + use<'a> {} //~^ WARN all possible in-scope parameters are already captured } diff --git a/tests/ui/impl-trait/precise-capturing/redundant.stderr b/tests/ui/impl-trait/precise-capturing/redundant.stderr index 325f04d3536a..274d9d2375f7 100644 --- a/tests/ui/impl-trait/precise-capturing/redundant.stderr +++ b/tests/ui/impl-trait/precise-capturing/redundant.stderr @@ -1,45 +1,36 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/redundant.rs:4:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 for more information - = note: `#[warn(incomplete_features)]` on by default - warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:7:19 + --> $DIR/redundant.rs:6:19 | -LL | fn hello<'a>() -> impl use<'a> Sized {} - | ^^^^^-------^^^^^^ - | | - | help: remove the `use<...>` syntax +LL | fn hello<'a>() -> impl Sized + use<'a> {} + | ^^^^^^^^^^^^^------- + | | + | help: remove the `use<...>` syntax | = note: `#[warn(impl_trait_redundant_captures)]` on by default warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:12:27 + --> $DIR/redundant.rs:11:27 | -LL | fn inherent(&self) -> impl use<'_> Sized {} - | ^^^^^-------^^^^^^ - | | - | help: remove the `use<...>` syntax +LL | fn inherent(&self) -> impl Sized + use<'_> {} + | ^^^^^^^^^^^^^------- + | | + | help: remove the `use<...>` syntax warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:17:22 + --> $DIR/redundant.rs:16:22 | -LL | fn in_trait() -> impl use<'a, Self> Sized; - | ^^^^^-------------^^^^^^ - | | - | help: remove the `use<...>` syntax +LL | fn in_trait() -> impl Sized + use<'a, Self>; + | ^^^^^^^^^^^^^------------- + | | + | help: remove the `use<...>` syntax warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:21:22 + --> $DIR/redundant.rs:20:22 | -LL | fn in_trait() -> impl use<'a> Sized {} - | ^^^^^-------^^^^^^ - | | - | help: remove the `use<...>` syntax +LL | fn in_trait() -> impl Sized + use<'a> {} + | ^^^^^^^^^^^^^------- + | | + | help: remove the `use<...>` syntax -warning: 5 warnings emitted +warning: 4 warnings emitted diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.rs b/tests/ui/impl-trait/precise-capturing/self-capture.rs index ecbc388e27be..e0a4a8b658c5 100644 --- a/tests/ui/impl-trait/precise-capturing/self-capture.rs +++ b/tests/ui/impl-trait/precise-capturing/self-capture.rs @@ -1,10 +1,9 @@ //@ check-pass #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete trait Foo { - fn bar<'a>() -> impl use Sized; + fn bar<'a>() -> impl Sized + use; } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.stderr b/tests/ui/impl-trait/precise-capturing/self-capture.stderr deleted file mode 100644 index 5a058c6826d2..000000000000 --- a/tests/ui/impl-trait/precise-capturing/self-capture.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/self-capture.rs:3:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/impl-trait/precise-capturing/unexpected-token.rs b/tests/ui/impl-trait/precise-capturing/unexpected-token.rs index 39c8c0def6bf..a1089fd7bfc5 100644 --- a/tests/ui/impl-trait/precise-capturing/unexpected-token.rs +++ b/tests/ui/impl-trait/precise-capturing/unexpected-token.rs @@ -2,8 +2,7 @@ // token due to a strange interaction between the sequence parsing code and the // param/lifetime parsing code. -fn hello() -> impl use<'a {}> Sized {} +fn hello() -> impl Sized + use<'a {}> {} //~^ ERROR expected one of `,` or `>`, found `{` -//~| ERROR expected item, found `>` fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr b/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr index 989c479b2484..51e4f0f67754 100644 --- a/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr +++ b/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr @@ -1,16 +1,8 @@ error: expected one of `,` or `>`, found `{` - --> $DIR/unexpected-token.rs:5:27 + --> $DIR/unexpected-token.rs:5:35 | -LL | fn hello() -> impl use<'a {}> Sized {} - | ^ expected one of `,` or `>` +LL | fn hello() -> impl Sized + use<'a {}> {} + | ^ expected one of `,` or `>` -error: expected item, found `>` - --> $DIR/unexpected-token.rs:5:29 - | -LL | fn hello() -> impl use<'a {}> Sized {} - | ^ expected item - | - = note: for a full list of items that can appear in modules, see - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/instrument-coverage/coverage-options.bad.stderr b/tests/ui/instrument-coverage/coverage-options.bad.stderr index 4a272cf97fb0..1a6b30dc8324 100644 --- a/tests/ui/instrument-coverage/coverage-options.bad.stderr +++ b/tests/ui/instrument-coverage/coverage-options.bad.stderr @@ -1,2 +1,2 @@ -error: incorrect value `bad` for unstable option `coverage-options` - `block` | `branch` | `condition` | `mcdc` was expected +error: incorrect value `bad` for unstable option `coverage-options` - `block` | `branch` | `condition` | `mcdc` | `no-mir-spans` was expected diff --git a/tests/ui/issues/issue-14915.stderr b/tests/ui/issues/issue-14915.stderr index 279f5772d21d..3558bd651c62 100644 --- a/tests/ui/issues/issue-14915.stderr +++ b/tests/ui/issues/issue-14915.stderr @@ -5,6 +5,12 @@ LL | println!("{}", x + 1); | - ^ - {integer} | | | Box + | +note: the foreign item type `Box` doesn't implement `Add<{integer}>` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL + | + = note: not implement `Add<{integer}>` error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-66706.rs b/tests/ui/issues/issue-66706.rs index 6d1d9f5e3a99..87dc3437a57b 100644 --- a/tests/ui/issues/issue-66706.rs +++ b/tests/ui/issues/issue-66706.rs @@ -1,6 +1,6 @@ fn a() { [0; [|_: _ &_| ()].len()] - //~^ ERROR expected `,`, found `&` + //~^ ERROR expected one of `,` or `|`, found `&` //~| ERROR type annotations needed } @@ -11,7 +11,7 @@ fn b() { fn c() { [0; [|&_: _ &_| {}; 0 ].len()] - //~^ ERROR expected `,`, found `&` + //~^ ERROR expected one of `,` or `|`, found `&` //~| ERROR type annotations needed } diff --git a/tests/ui/issues/issue-66706.stderr b/tests/ui/issues/issue-66706.stderr index 0271db754bd3..dd1e07589f51 100644 --- a/tests/ui/issues/issue-66706.stderr +++ b/tests/ui/issues/issue-66706.stderr @@ -1,8 +1,8 @@ -error: expected `,`, found `&` +error: expected one of `,` or `|`, found `&` --> $DIR/issue-66706.rs:2:16 | LL | [0; [|_: _ &_| ()].len()] - | -^ expected `,` + | -^ expected one of `,` or `|` | | | help: missing `,` @@ -12,11 +12,11 @@ error: expected identifier, found reserved identifier `_` LL | [0; [|f @ &ref _| {} ; 0 ].len() ]; | ^ expected identifier, found reserved identifier -error: expected `,`, found `&` +error: expected one of `,` or `|`, found `&` --> $DIR/issue-66706.rs:13:17 | LL | [0; [|&_: _ &_| {}; 0 ].len()] - | -^ expected `,` + | -^ expected one of `,` or `|` | | | help: missing `,` diff --git a/tests/ui/minus-string.stderr b/tests/ui/minus-string.stderr index 105274ee7d0e..cf63ec244167 100644 --- a/tests/ui/minus-string.stderr +++ b/tests/ui/minus-string.stderr @@ -3,6 +3,11 @@ error[E0600]: cannot apply unary operator `-` to type `String` | LL | fn main() { -"foo".to_string(); } | ^^^^^^^^^^^^^^^^^^ cannot apply unary operator `-` + | +note: the foreign item type `String` doesn't implement `Neg` + --> $SRC_DIR/alloc/src/string.rs:LL:COL + | + = note: not implement `Neg` error: aborting due to 1 previous error diff --git a/tests/ui/parser/trait-object-delimiters.rs b/tests/ui/parser/trait-object-delimiters.rs index d6bc629aa114..8f6221c1b943 100644 --- a/tests/ui/parser/trait-object-delimiters.rs +++ b/tests/ui/parser/trait-object-delimiters.rs @@ -8,7 +8,7 @@ fn foo2(_: &dyn (Drop + AsRef)) {} //~ ERROR incorrect parentheses around t fn foo2_no_space(_: &dyn(Drop + AsRef)) {} //~ ERROR incorrect parentheses around trait bounds fn foo3(_: &dyn {Drop + AsRef}) {} //~ ERROR expected parameter name, found `{` -//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `~`, lifetime, or path, found `{` +//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `use`, `~`, lifetime, or path, found `{` //~| ERROR at least one trait is required for an object type fn foo4(_: &dyn >) {} //~ ERROR expected identifier, found `<` diff --git a/tests/ui/parser/trait-object-delimiters.stderr b/tests/ui/parser/trait-object-delimiters.stderr index 2b1f8df991f4..5f175e86545a 100644 --- a/tests/ui/parser/trait-object-delimiters.stderr +++ b/tests/ui/parser/trait-object-delimiters.stderr @@ -34,11 +34,11 @@ error: expected parameter name, found `{` LL | fn foo3(_: &dyn {Drop + AsRef}) {} | ^ expected parameter name -error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `~`, lifetime, or path, found `{` +error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `use`, `~`, lifetime, or path, found `{` --> $DIR/trait-object-delimiters.rs:10:17 | LL | fn foo3(_: &dyn {Drop + AsRef}) {} - | -^ expected one of 12 possible tokens + | -^ expected one of 13 possible tokens | | | help: missing `,` diff --git a/tests/ui/pattern/pattern-tyvar-2.stderr b/tests/ui/pattern/pattern-tyvar-2.stderr index c6540e795589..be52fa8b2394 100644 --- a/tests/ui/pattern/pattern-tyvar-2.stderr +++ b/tests/ui/pattern/pattern-tyvar-2.stderr @@ -5,6 +5,11 @@ LL | fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; | - ^ - {integer} | | | Vec + | +note: the foreign item type `Vec` doesn't implement `Mul<{integer}>` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + | + = note: not implement `Mul<{integer}>` error: aborting due to 1 previous error diff --git a/tests/ui/typeck/assign-non-lval-derefmut.stderr b/tests/ui/typeck/assign-non-lval-derefmut.stderr index b26d16da0152..ce0ff1d957b5 100644 --- a/tests/ui/typeck/assign-non-lval-derefmut.stderr +++ b/tests/ui/typeck/assign-non-lval-derefmut.stderr @@ -19,6 +19,10 @@ LL | x.lock().unwrap() += 1; | | | cannot use `+=` on type `MutexGuard<'_, usize>` | +note: the foreign item type `MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>` + --> $SRC_DIR/std/src/sync/mutex.rs:LL:COL + | + = note: not implement `AddAssign<{integer}>` help: `+=` can be used on `usize` if you dereference the left-hand side | LL | *x.lock().unwrap() += 1; @@ -47,6 +51,10 @@ LL | y += 1; | | | cannot use `+=` on type `MutexGuard<'_, usize>` | +note: the foreign item type `MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>` + --> $SRC_DIR/std/src/sync/mutex.rs:LL:COL + | + = note: not implement `AddAssign<{integer}>` help: `+=` can be used on `usize` if you dereference the left-hand side | LL | *y += 1;