diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src')
28 files changed, 529 insertions, 385 deletions
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index fdd547448f0..8e2137da655 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -738,7 +738,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { value.push_normal(", "); } - match arg.unpack() { + match arg.kind() { ty::GenericArgKind::Lifetime(lt) => { let s = lt.to_string(); value.push_normal(if s.is_empty() { "'_" } else { &s }); @@ -1166,7 +1166,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { for (i, (arg1, arg2)) in sub1.iter().zip(sub2).enumerate().take(len) { self.push_comma(&mut values.0, &mut values.1, i); - match arg1.unpack() { + match arg1.kind() { // At one point we'd like to elide all lifetimes here, they are // irrelevant for all diagnostics that use this output. // @@ -1509,7 +1509,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } let (is_simple_error, exp_found) = match values { ValuePairs::Terms(ExpectedFound { expected, found }) => { - match (expected.unpack(), found.unpack()) { + match (expected.kind(), found.kind()) { (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => { let is_simple_err = expected.is_simple_text() && found.is_simple_text(); @@ -2026,7 +2026,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } LetVisitor { span }.visit_body(body).break_value() } - hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(_, ty, _, _), .. }) => { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(_, _, ty, _), .. }) => { Some(&ty.peel_refs().kind) } _ => None, @@ -2156,7 +2156,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return None; } - Some(match (exp_found.expected.unpack(), exp_found.found.unpack()) { + Some(match (exp_found.expected.kind(), exp_found.found.kind()) { (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => { let (mut exp, mut fnd) = self.cmp(expected, found); // Use the terminal width as the basis to determine when to compress the printed diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index cb1c9c75369..bfef3340b32 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -215,7 +215,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ClosureEraser<'a, 'tcx> { // `_` because then we'd end up with `Vec<_, _>`, instead of // `Vec<_>`. arg - } else if let GenericArgKind::Type(_) = arg.unpack() { + } else if let GenericArgKind::Type(_) = arg.kind() { // We don't replace lifetime or const params, only type params. self.new_infer().into() } else { @@ -347,7 +347,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { highlight: ty::print::RegionHighlightMode<'tcx>, ) -> InferenceDiagnosticsData { let tcx = self.tcx; - match term.unpack() { + match term.kind() { TermKind::Ty(ty) => { if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() { let var_origin = self.infcx.type_var_origin(ty_vid); @@ -568,7 +568,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return arg; } - match arg.unpack() { + match arg.kind() { GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(), GenericArgKind::Const(_) => self.next_const_var(DUMMY_SP).into(), @@ -803,7 +803,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { } impl<'tcx> CostCtxt<'tcx> { fn arg_cost(self, arg: GenericArg<'tcx>) -> usize { - match arg.unpack() { + match arg.kind() { GenericArgKind::Lifetime(_) => 0, // erased GenericArgKind::Type(ty) => self.ty_cost(ty), GenericArgKind::Const(_) => 3, // some non-zero value @@ -898,7 +898,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { return true; } - match (arg.unpack(), self.target.unpack()) { + match (arg.kind(), self.target.kind()) { (GenericArgKind::Type(inner_ty), TermKind::Ty(target_ty)) => { use ty::{Infer, TyVar}; match (inner_ty.kind(), target_ty.kind()) { @@ -929,7 +929,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { if self.generic_arg_is_target(inner) { return true; } - match inner.unpack() { + match inner.kind() { GenericArgKind::Lifetime(_) => {} GenericArgKind::Type(ty) => { if matches!( diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index cdbb92f4c7b..3804c13acce 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -664,8 +664,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let Some(found) = exp_found.found.args.get(1) else { return; }; - let expected = expected.unpack(); - let found = found.unpack(); + let expected = expected.kind(); + let found = found.kind(); // 3. Extract the tuple type from Fn trait and suggest the change. if let GenericArgKind::Type(expected) = expected && let GenericArgKind::Type(found) = found diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 970160ba212..9b5e421e0e4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -841,16 +841,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return None; }; - let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() { + let (closure_def_id, found_args, has_self_borrows) = match *self_ty.kind() { ty::Closure(def_id, args) => { - (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None) + (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), false) } ty::CoroutineClosure(def_id, args) => ( def_id, args.as_coroutine_closure() .coroutine_closure_sig() .map_bound(|sig| sig.tupled_inputs_ty), - Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()), + !args.as_coroutine_closure().tupled_upvars_ty().is_ty_var() + && args.as_coroutine_closure().has_self_borrows(), ), _ => return None, }; @@ -884,10 +885,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // If the closure has captures, then perhaps the reason that the trait // is unimplemented is because async closures don't implement `Fn`/`FnMut` // if they have captures. - if let Some(by_ref_captures) = by_ref_captures - && let ty::FnPtr(sig_tys, _) = by_ref_captures.kind() - && !sig_tys.skip_binder().output().is_unit() - { + if has_self_borrows && expected_kind != ty::ClosureKind::FnOnce { let mut err = self.dcx().create_err(AsyncClosureNotFn { span: self.tcx.def_span(closure_def_id), kind: expected_kind.as_str(), @@ -1503,11 +1501,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return None; }; - let Ok(Some(ImplSource::UserDefined(impl_data))) = SelectionContext::new(self) - .poly_select(&obligation.with( - self.tcx, - predicate.kind().rebind(proj.projection_term.trait_ref(self.tcx)), - )) + let trait_ref = self.enter_forall_and_leak_universe( + predicate.kind().rebind(proj.projection_term.trait_ref(self.tcx)), + ); + let Ok(Some(ImplSource::UserDefined(impl_data))) = + SelectionContext::new(self).select(&obligation.with(self.tcx, trait_ref)) else { return None; }; @@ -2448,7 +2446,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } if let ty::Adt(def, args) = self_ty.kind() && let [arg] = &args[..] - && let ty::GenericArgKind::Type(ty) = arg.unpack() + && let ty::GenericArgKind::Type(ty) = arg.kind() && let ty::Adt(inner_def, _) = ty.kind() && inner_def == def { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index d5ee6e2123a..37968386e9a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -429,7 +429,19 @@ impl<'tcx> OnUnimplementedDirective { .next() .ok_or_else(|| tcx.dcx().emit_err(InvalidOnClause::Empty { span }))?; - match OnUnimplementedCondition::parse(cond) { + let generics: Vec<Symbol> = tcx + .generics_of(item_def_id) + .own_params + .iter() + .filter_map(|param| { + if matches!(param.kind, GenericParamDefKind::Lifetime) { + None + } else { + Some(param.name) + } + }) + .collect(); + match OnUnimplementedCondition::parse(cond, &generics) { Ok(condition) => Some(condition), Err(e) => return Err(tcx.dcx().emit_err(e)), } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs index 13753761f09..e8ea9f2d23e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs @@ -26,9 +26,12 @@ impl OnUnimplementedCondition { }) } - pub(crate) fn parse(input: &MetaItemInner) -> Result<Self, InvalidOnClause> { + pub(crate) fn parse( + input: &MetaItemInner, + generics: &[Symbol], + ) -> Result<Self, InvalidOnClause> { let span = input.span(); - let pred = Predicate::parse(input)?; + let pred = Predicate::parse(input, generics)?; Ok(OnUnimplementedCondition { span, pred }) } } @@ -52,7 +55,7 @@ enum Predicate { } impl Predicate { - fn parse(input: &MetaItemInner) -> Result<Self, InvalidOnClause> { + fn parse(input: &MetaItemInner, generics: &[Symbol]) -> Result<Self, InvalidOnClause> { let meta_item = match input { MetaItemInner::MetaItem(meta_item) => meta_item, MetaItemInner::Lit(lit) => { @@ -69,10 +72,10 @@ impl Predicate { match meta_item.kind { MetaItemKind::List(ref mis) => match predicate.name { - sym::any => Ok(Predicate::Any(Predicate::parse_sequence(mis)?)), - sym::all => Ok(Predicate::All(Predicate::parse_sequence(mis)?)), + sym::any => Ok(Predicate::Any(Predicate::parse_sequence(mis, generics)?)), + sym::all => Ok(Predicate::All(Predicate::parse_sequence(mis, generics)?)), sym::not => match &**mis { - [one] => Ok(Predicate::Not(Box::new(Predicate::parse(one)?))), + [one] => Ok(Predicate::Not(Box::new(Predicate::parse(one, generics)?))), [first, .., last] => Err(InvalidOnClause::ExpectedOnePredInNot { span: first.span().to(last.span()), }), @@ -83,7 +86,7 @@ impl Predicate { } }, MetaItemKind::NameValue(MetaItemLit { symbol, .. }) => { - let name = Name::parse(predicate); + let name = Name::parse(predicate, generics)?; let value = FilterFormatString::parse(symbol); let kv = NameValue { name, value }; Ok(Predicate::Match(kv)) @@ -95,8 +98,11 @@ impl Predicate { } } - fn parse_sequence(sequence: &[MetaItemInner]) -> Result<Vec<Self>, InvalidOnClause> { - sequence.iter().map(Predicate::parse).collect() + fn parse_sequence( + sequence: &[MetaItemInner], + generics: &[Symbol], + ) -> Result<Vec<Self>, InvalidOnClause> { + sequence.iter().map(|item| Predicate::parse(item, generics)).collect() } fn eval(&self, eval: &mut impl FnMut(FlagOrNv<'_>) -> bool) -> bool { @@ -156,14 +162,13 @@ enum Name { } impl Name { - fn parse(Ident { name, .. }: Ident) -> Self { + fn parse(Ident { name, span }: Ident, generics: &[Symbol]) -> Result<Self, InvalidOnClause> { match name { - sym::_Self | kw::SelfUpper => Name::SelfUpper, - sym::from_desugaring => Name::FromDesugaring, - sym::cause => Name::Cause, - // FIXME(mejrs) Perhaps we should start checking that - // this actually is a valid generic parameter? - generic => Name::GenericArg(generic), + kw::SelfUpper => Ok(Name::SelfUpper), + sym::from_desugaring => Ok(Name::FromDesugaring), + sym::cause => Ok(Name::Cause), + generic if generics.contains(&generic) => Ok(Name::GenericArg(generic)), + invalid_name => Err(InvalidOnClause::InvalidName { invalid_name, span }), } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs index ce170f820e1..7c1dfc1728f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs @@ -2,8 +2,8 @@ use std::fmt; use std::ops::Range; use errors::*; -use rustc_middle::ty::TyCtxt; use rustc_middle::ty::print::TraitRefPrintSugared; +use rustc_middle::ty::{GenericParamDefKind, TyCtxt}; use rustc_parse_format::{ Alignment, Argument, Count, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position, @@ -232,48 +232,16 @@ fn parse_arg<'tcx>( ) -> FormatArg { let (Ctx::RustcOnUnimplemented { tcx, trait_def_id } | Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }) = ctx; - let trait_name = tcx.item_ident(*trait_def_id); - let generics = tcx.generics_of(trait_def_id); + let span = slice_span(input_span, arg.position_span.clone()); match arg.position { // Something like "hello {name}" Position::ArgumentNamed(name) => match (ctx, Symbol::intern(name)) { - // accepted, but deprecated - (Ctx::RustcOnUnimplemented { .. }, sym::_Self) => { - warnings - .push(FormatWarning::FutureIncompat { span, help: String::from("use {Self}") }); - FormatArg::SelfUpper - } - ( - Ctx::RustcOnUnimplemented { .. }, - sym::from_desugaring - | sym::crate_local - | sym::direct - | sym::cause - | sym::float - | sym::integer_ - | sym::integral, - ) => { - warnings.push(FormatWarning::FutureIncompat { - span, - help: String::from("don't use this in a format string"), - }); - FormatArg::AsIs(String::new()) - } - // Only `#[rustc_on_unimplemented]` can use these (Ctx::RustcOnUnimplemented { .. }, sym::ItemContext) => FormatArg::ItemContext, (Ctx::RustcOnUnimplemented { .. }, sym::This) => FormatArg::This, (Ctx::RustcOnUnimplemented { .. }, sym::Trait) => FormatArg::Trait, - // `{ThisTraitsName}`. Some attrs in std use this, but I'd like to change it to the more general `{This}` - // because that'll be simpler to parse and extend in the future - (Ctx::RustcOnUnimplemented { .. }, name) if name == trait_name.name => { - warnings - .push(FormatWarning::FutureIncompat { span, help: String::from("use {This}") }); - FormatArg::This - } - // Any attribute can use these ( Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. }, @@ -282,7 +250,10 @@ fn parse_arg<'tcx>( ( Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. }, generic_param, - ) if generics.own_params.iter().any(|param| param.name == generic_param) => { + ) if tcx.generics_of(trait_def_id).own_params.iter().any(|param| { + !matches!(param.kind, GenericParamDefKind::Lifetime) && param.name == generic_param + }) => + { FormatArg::GenericParam { generic_param } } @@ -375,39 +346,4 @@ pub mod errors { #[diag(trait_selection_missing_options_for_on_unimplemented_attr)] #[help] pub struct MissingOptionsForOnUnimplementedAttr; - - #[derive(LintDiagnostic)] - #[diag(trait_selection_ignored_diagnostic_option)] - pub struct IgnoredDiagnosticOption { - pub option_name: &'static str, - #[label] - pub span: Span, - #[label(trait_selection_other_label)] - pub prev_span: Span, - } - - impl IgnoredDiagnosticOption { - pub fn maybe_emit_warning<'tcx>( - tcx: TyCtxt<'tcx>, - item_def_id: DefId, - new: Option<Span>, - old: Option<Span>, - option_name: &'static str, - ) { - if let (Some(new_item), Some(old_item)) = (new, old) { - if let Some(item_def_id) = item_def_id.as_local() { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id), - new_item, - IgnoredDiagnosticOption { - span: new_item, - prev_span: old_item, - option_name, - }, - ); - } - } - } - } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 8801397b775..c4f1f7d712a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -351,14 +351,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::Node::Item(hir::Item { kind: - hir::ItemKind::Struct(_, _, generics) - | hir::ItemKind::Enum(_, _, generics) - | hir::ItemKind::Union(_, _, generics) + hir::ItemKind::Struct(_, generics, _) + | hir::ItemKind::Enum(_, generics, _) + | hir::ItemKind::Union(_, generics, _) | hir::ItemKind::Trait(_, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn { generics, .. } - | hir::ItemKind::TyAlias(_, _, generics) - | hir::ItemKind::Const(_, _, generics, _) + | hir::ItemKind::TyAlias(_, generics, _) + | hir::ItemKind::Const(_, generics, _, _) | hir::ItemKind::TraitAlias(_, generics, _), .. }) @@ -411,14 +411,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::Node::Item(hir::Item { kind: - hir::ItemKind::Struct(_, _, generics) - | hir::ItemKind::Enum(_, _, generics) - | hir::ItemKind::Union(_, _, generics) + hir::ItemKind::Struct(_, generics, _) + | hir::ItemKind::Enum(_, generics, _) + | hir::ItemKind::Union(_, generics, _) | hir::ItemKind::Trait(_, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn { generics, .. } - | hir::ItemKind::TyAlias(_, _, generics) - | hir::ItemKind::Const(_, _, generics, _) + | hir::ItemKind::TyAlias(_, generics, _) + | hir::ItemKind::Const(_, generics, _, _) | hir::ItemKind::TraitAlias(_, generics, _), .. }) if !param_ty => { @@ -2124,16 +2124,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { accessed through a specific `impl`", self.tcx.def_kind_descr(assoc_item.as_def_kind(), item_def_id) )); - err.span_suggestion( - span, - "use the fully qualified path to an implementation", - format!( - "<Type as {}>::{}", - self.tcx.def_path_str(trait_ref), - assoc_item.name() - ), - Applicability::HasPlaceholders, - ); + + if !assoc_item.is_impl_trait_in_trait() { + err.span_suggestion( + span, + "use the fully qualified path to an implementation", + format!( + "<Type as {}>::{}", + self.tcx.def_path_str(trait_ref), + assoc_item.name() + ), + Applicability::HasPlaceholders, + ); + } } } } diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 8ab4d795c45..779c861637a 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -72,6 +72,13 @@ pub enum InvalidOnClause { span: Span, invalid_flag: Symbol, }, + #[diag(trait_selection_rustc_on_unimplemented_invalid_name, code = E0232)] + InvalidName { + #[primary_span] + #[label] + span: Span, + invalid_name: Symbol, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 332204a0c5f..d5bde9192d5 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -81,7 +81,7 @@ pub fn check_opaque_type_parameter_valid<'tcx>( } for (i, arg) in opaque_type_key.iter_captured_args(tcx) { - let arg_is_param = match arg.unpack() { + let arg_is_param = match arg.kind() { GenericArgKind::Lifetime(lt) => match defining_scope_kind { DefiningScopeKind::HirTypeck => continue, DefiningScopeKind::MirBorrowck => { diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 3601c2cba9b..e92e37b8738 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -1,19 +1,22 @@ use std::ops::Deref; use rustc_data_structures::fx::FxHashSet; +use rustc_hir::LangItem; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::{ - Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues, + Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarKind, CanonicalVarValues, }; -use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt}; +use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt}; use rustc_infer::traits::solve::Goal; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::Certainty; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, TypingMode}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitableExt as _, TypingMode, +}; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; -use crate::traits::{EvaluateConstErr, specialization_graph}; +use crate::traits::{EvaluateConstErr, ObligationCause, specialization_graph}; #[repr(transparent)] pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>); @@ -55,12 +58,73 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< (SolverDelegate(infcx), value, vars) } + fn compute_goal_fast_path( + &self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + span: Span, + ) -> Option<Certainty> { + if let Some(trait_pred) = goal.predicate.as_trait_clause() { + if trait_pred.polarity() == ty::PredicatePolarity::Positive { + match self.0.tcx.as_lang_item(trait_pred.def_id()) { + Some(LangItem::Sized) + if self + .resolve_vars_if_possible(trait_pred.self_ty().skip_binder()) + .is_trivially_sized(self.0.tcx) => + { + return Some(Certainty::Yes); + } + Some(LangItem::Copy | LangItem::Clone) => { + let self_ty = + self.resolve_vars_if_possible(trait_pred.self_ty().skip_binder()); + // Unlike `Sized` traits, which always prefer the built-in impl, + // `Copy`/`Clone` may be shadowed by a param-env candidate which + // could force a lifetime error or guide inference. While that's + // not generally desirable, it is observable, so for now let's + // ignore this fast path for types that have regions or infer. + if !self_ty + .has_type_flags(TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_INFER) + && self_ty.is_trivially_pure_clone_copy() + { + return Some(Certainty::Yes); + } + } + _ => {} + } + } + } + + let pred = goal.predicate.kind(); + match pred.no_bound_vars()? { + ty::PredicateKind::DynCompatible(def_id) if self.0.tcx.is_dyn_compatible(def_id) => { + Some(Certainty::Yes) + } + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(outlives)) => { + self.0.sub_regions( + SubregionOrigin::RelateRegionParamBound(span, None), + outlives.1, + outlives.0, + ); + Some(Certainty::Yes) + } + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => { + self.0.register_type_outlives_constraint( + outlives.0, + outlives.1, + &ObligationCause::dummy_with_span(span), + ); + + Some(Certainty::Yes) + } + _ => None, + } + } + fn fresh_var_for_kind_with_span( &self, arg: ty::GenericArg<'tcx>, span: Span, ) -> ty::GenericArg<'tcx> { - match arg.unpack() { + match arg.kind() { ty::GenericArgKind::Lifetime(_) => { self.next_region_var(RegionVariableOrigin::MiscVariable(span)).into() } @@ -142,11 +206,11 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< fn instantiate_canonical_var_with_infer( &self, - cv_info: CanonicalVarInfo<'tcx>, + kind: CanonicalVarKind<'tcx>, span: Span, universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, ) -> ty::GenericArg<'tcx> { - self.0.instantiate_canonical_var(span, cv_info, universe_map) + self.0.instantiate_canonical_var(span, kind, universe_map) } fn add_item_bounds_for_hidden_type( diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 3e1cdac84df..ed99c678a4d 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -12,8 +12,12 @@ use rustc_infer::traits::{ use rustc_middle::ty::{ self, DelayedSet, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode, }; -use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _}; +use rustc_next_trait_solver::delegate::SolverDelegate as _; +use rustc_next_trait_solver::solve::{ + GenerateProofTree, GoalEvaluation, GoalStalledOn, HasChanged, SolverDelegateEvalExt as _, +}; use rustc_span::Span; +use thin_vec::ThinVec; use tracing::instrument; use self::derive_errors::*; @@ -24,6 +28,10 @@ use crate::traits::{FulfillmentError, ScrubbedTraitError}; mod derive_errors; +// FIXME: Do we need to use a `ThinVec` here? +type PendingObligations<'tcx> = + ThinVec<(PredicateObligation<'tcx>, Option<GoalStalledOn<TyCtxt<'tcx>>>)>; + /// A trait engine using the new trait solver. /// /// This is mostly identical to how `evaluate_all` works inside of the @@ -53,13 +61,17 @@ struct ObligationStorage<'tcx> { /// We cannot eagerly return these as error so we instead store them here /// to avoid recomputing them each time `select_where_possible` is called. /// This also allows us to return the correct `FulfillmentError` for them. - overflowed: PredicateObligations<'tcx>, - pending: PredicateObligations<'tcx>, + overflowed: Vec<PredicateObligation<'tcx>>, + pending: PendingObligations<'tcx>, } impl<'tcx> ObligationStorage<'tcx> { - fn register(&mut self, obligation: PredicateObligation<'tcx>) { - self.pending.push(obligation); + fn register( + &mut self, + obligation: PredicateObligation<'tcx>, + stalled_on: Option<GoalStalledOn<TyCtxt<'tcx>>>, + ) { + self.pending.push((obligation, stalled_on)); } fn has_pending_obligations(&self) -> bool { @@ -67,7 +79,8 @@ impl<'tcx> ObligationStorage<'tcx> { } fn clone_pending(&self) -> PredicateObligations<'tcx> { - let mut obligations = self.pending.clone(); + let mut obligations: PredicateObligations<'tcx> = + self.pending.iter().map(|(o, _)| o.clone()).collect(); obligations.extend(self.overflowed.iter().cloned()); obligations } @@ -75,8 +88,9 @@ impl<'tcx> ObligationStorage<'tcx> { fn drain_pending( &mut self, cond: impl Fn(&PredicateObligation<'tcx>) -> bool, - ) -> PredicateObligations<'tcx> { - let (unstalled, pending) = mem::take(&mut self.pending).into_iter().partition(cond); + ) -> PendingObligations<'tcx> { + let (unstalled, pending) = + mem::take(&mut self.pending).into_iter().partition(|(o, _)| cond(o)); self.pending = pending; unstalled } @@ -89,13 +103,21 @@ impl<'tcx> ObligationStorage<'tcx> { // we were to do another step of `select_where_possible`, which goals would // change. // FIXME: <https://github.com/Gankra/thin-vec/pull/66> is merged, this can be removed. - self.overflowed.extend(ExtractIf::new(&mut self.pending, |o| { - let goal = o.as_goal(); - let result = <&SolverDelegate<'tcx>>::from(infcx) - .evaluate_root_goal(goal, GenerateProofTree::No, o.cause.span) - .0; - matches!(result, Ok((HasChanged::Yes, _))) - })); + self.overflowed.extend( + ExtractIf::new(&mut self.pending, |(o, stalled_on)| { + let goal = o.as_goal(); + let result = <&SolverDelegate<'tcx>>::from(infcx) + .evaluate_root_goal( + goal, + GenerateProofTree::No, + o.cause.span, + stalled_on.take(), + ) + .0; + matches!(result, Ok(GoalEvaluation { has_changed: HasChanged::Yes, .. })) + }) + .map(|(o, _)| o), + ); }) } } @@ -118,11 +140,11 @@ impl<'tcx, E: 'tcx> FulfillmentCtxt<'tcx, E> { &self, infcx: &InferCtxt<'tcx>, obligation: &PredicateObligation<'tcx>, - result: &Result<(HasChanged, Certainty), NoSolution>, + result: &Result<GoalEvaluation<TyCtxt<'tcx>>, NoSolution>, ) { if let Some(inspector) = infcx.obligation_inspector.get() { let result = match result { - Ok((_, c)) => Ok(*c), + Ok(GoalEvaluation { certainty, .. }) => Ok(*certainty), Err(NoSolution) => Err(NoSolution), }; (inspector)(infcx, &obligation, result); @@ -141,14 +163,14 @@ where obligation: PredicateObligation<'tcx>, ) { assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); - self.obligations.register(obligation); + self.obligations.register(obligation, None); } fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> { self.obligations .pending .drain(..) - .map(|obligation| NextSolverError::Ambiguity(obligation)) + .map(|(obligation, _)| NextSolverError::Ambiguity(obligation)) .chain( self.obligations .overflowed @@ -163,8 +185,8 @@ where assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); let mut errors = Vec::new(); loop { - let mut has_changed = false; - for mut obligation in self.obligations.drain_pending(|_| true) { + let mut any_changed = false; + for (mut obligation, stalled_on) in self.obligations.drain_pending(|_| true) { if !infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) { self.obligations.on_fulfillment_overflow(infcx); // Only return true errors that we have accumulated while processing. @@ -172,11 +194,29 @@ where } let goal = obligation.as_goal(); - let result = <&SolverDelegate<'tcx>>::from(infcx) - .evaluate_root_goal(goal, GenerateProofTree::No, obligation.cause.span) + let delegate = <&SolverDelegate<'tcx>>::from(infcx); + if let Some(certainty) = + delegate.compute_goal_fast_path(goal, obligation.cause.span) + { + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => { + self.obligations.register(obligation, None); + } + } + continue; + } + + let result = delegate + .evaluate_root_goal( + goal, + GenerateProofTree::No, + obligation.cause.span, + stalled_on, + ) .0; self.inspect_evaluated_obligation(infcx, &obligation, &result); - let (changed, certainty) = match result { + let GoalEvaluation { certainty, has_changed, stalled_on } = match result { Ok(result) => result, Err(NoSolution) => { errors.push(E::from_solver_error( @@ -187,7 +227,7 @@ where } }; - if changed == HasChanged::Yes { + if has_changed == HasChanged::Yes { // We increment the recursion depth here to track the number of times // this goal has resulted in inference progress. This doesn't precisely // model the way that we track recursion depth in the old solver due @@ -195,16 +235,16 @@ where // approximation and should only result in fulfillment overflow in // pathological cases. obligation.recursion_depth += 1; - has_changed = true; + any_changed = true; } match certainty { Certainty::Yes => {} - Certainty::Maybe(_) => self.obligations.register(obligation), + Certainty::Maybe(_) => self.obligations.register(obligation, stalled_on), } } - if !has_changed { + if !any_changed { break; } } @@ -238,20 +278,24 @@ where return Default::default(); } - self.obligations.drain_pending(|obl| { - infcx.probe(|_| { - infcx - .visit_proof_tree( - obl.as_goal(), - &mut StalledOnCoroutines { - stalled_generators, - span: obl.cause.span, - cache: Default::default(), - }, - ) - .is_break() + self.obligations + .drain_pending(|obl| { + infcx.probe(|_| { + infcx + .visit_proof_tree( + obl.as_goal(), + &mut StalledOnCoroutines { + stalled_generators, + span: obl.cause.span, + cache: Default::default(), + }, + ) + .is_break() + }) }) - }) + .into_iter() + .map(|(o, _)| o) + .collect() } } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index f64cd5ffebe..1c9d69da322 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -11,7 +11,9 @@ use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _}; +use rustc_next_trait_solver::solve::{ + GenerateProofTree, GoalEvaluation, SolverDelegateEvalExt as _, +}; use tracing::{instrument, trace}; use crate::solve::delegate::SolverDelegate; @@ -93,19 +95,21 @@ pub(super) fn fulfillment_error_for_stalled<'tcx>( root_obligation.as_goal(), GenerateProofTree::No, root_obligation.cause.span, + None, ) .0 { - Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => { + Ok(GoalEvaluation { certainty: Certainty::Maybe(MaybeCause::Ambiguity), .. }) => { (FulfillmentErrorCode::Ambiguity { overflow: None }, true) } - Ok(( - _, - Certainty::Maybe(MaybeCause::Overflow { - suggest_increasing_limit, - keep_constraints: _, - }), - )) => ( + Ok(GoalEvaluation { + certainty: + Certainty::Maybe(MaybeCause::Overflow { + suggest_increasing_limit, + keep_constraints: _, + }), + .. + }) => ( FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) }, // Don't look into overflows because we treat overflows weirdly anyways. // We discard the inference constraints from overflowing goals, so @@ -115,7 +119,7 @@ pub(super) fn fulfillment_error_for_stalled<'tcx>( // FIXME: We should probably just look into overflows here. false, ), - Ok((_, Certainty::Yes)) => { + Ok(GoalEvaluation { certainty: Certainty::Yes, .. }) => { bug!( "did not expect successful goal when collecting ambiguity errors for `{:?}`", infcx.resolve_vars_if_possible(root_obligation.predicate), diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 9795655e842..1193a9059ca 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -15,9 +15,9 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_macros::extension; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; -use rustc_middle::ty::{TyCtxt, TypeFoldable, VisitorResult, try_visit}; +use rustc_middle::ty::{TyCtxt, VisitorResult, try_visit}; use rustc_middle::{bug, ty}; -use rustc_next_trait_solver::resolve::EagerResolver; +use rustc_next_trait_solver::resolve::eager_resolve_vars; use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state}; use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _}; use rustc_span::{DUMMY_SP, Span}; @@ -187,8 +187,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { let _ = term_hack.constrain(infcx, span, param_env); } - let opt_impl_args = - opt_impl_args.map(|impl_args| impl_args.fold_with(&mut EagerResolver::new(infcx))); + let opt_impl_args = opt_impl_args.map(|impl_args| eager_resolve_vars(infcx, impl_args)); let goals = instantiated_goals .into_iter() @@ -207,7 +206,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { let infcx = self.goal.infcx; match goal.predicate.kind().no_bound_vars() { Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => { - let unconstrained_term = match term.unpack() { + let unconstrained_term = match term.kind() { ty::TermKind::Ty(_) => infcx.next_ty_var(span).into(), ty::TermKind::Const(_) => infcx.next_const_var(span).into(), }; @@ -219,8 +218,8 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { // building their proof tree, the expected term was unconstrained, but when // instantiating the candidate it is already constrained to the result of another // candidate. - let proof_tree = - infcx.probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes).1); + let proof_tree = infcx + .probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes, None).1); InspectGoal::new( infcx, self.goal.depth + 1, @@ -236,7 +235,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { // constraints, we get an ICE if we already applied the constraints // from the chosen candidate. let proof_tree = infcx - .probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes, span).1) + .probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes, span, None).1) .unwrap(); InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source) } @@ -392,7 +391,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { infcx, depth, orig_values, - goal: uncanonicalized_goal.fold_with(&mut EagerResolver::new(infcx)), + goal: eager_resolve_vars(infcx, uncanonicalized_goal), result, evaluation_kind: evaluation.kind, normalizes_to_term_hack, @@ -442,6 +441,7 @@ impl<'tcx> InferCtxt<'tcx> { goal, GenerateProofTree::Yes, visitor.span(), + None, ); 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/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs index 4fdaf740287..21812c8017d 100644 --- a/compiler/rustc_trait_selection/src/solve/select.rs +++ b/compiler/rustc_trait_selection/src/solve/select.rs @@ -5,7 +5,7 @@ use rustc_infer::traits::solve::inspect::ProbeKind; use rustc_infer::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_infer::traits::{ BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, Obligation, ObligationCause, - PolyTraitObligation, Selection, SelectionError, SelectionResult, + Selection, SelectionError, SelectionResult, TraitObligation, }; use rustc_macros::extension; use rustc_middle::{bug, span_bug}; @@ -15,9 +15,10 @@ use crate::solve::inspect::{self, ProofTreeInferCtxtExt}; #[extension(pub trait InferCtxtSelectExt<'tcx>)] impl<'tcx> InferCtxt<'tcx> { + /// Do not use this directly. This is called from [`crate::traits::SelectionContext::select`]. fn select_in_new_trait_solver( &self, - obligation: &PolyTraitObligation<'tcx>, + obligation: &TraitObligation<'tcx>, ) -> SelectionResult<'tcx, Selection<'tcx>> { assert!(self.next_trait_solver()); diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 02521c9453d..3ae908ec16b 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -726,7 +726,9 @@ impl<'tcx> AutoTraitFinder<'tcx> { } ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(binder)) => { let binder = bound_predicate.rebind(binder); - selcx.infcx.region_outlives_predicate(&dummy_cause, binder) + selcx.infcx.enter_forall(binder, |pred| { + selcx.infcx.register_region_outlives_constraint(pred, &dummy_cause); + }); } ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(binder)) => { let binder = bound_predicate.rebind(binder); @@ -735,14 +737,14 @@ impl<'tcx> AutoTraitFinder<'tcx> { binder.map_bound_ref(|pred| pred.0).no_bound_vars(), ) { (None, Some(t_a)) => { - selcx.infcx.register_region_obligation_with_cause( + selcx.infcx.register_type_outlives_constraint( t_a, selcx.infcx.tcx.lifetimes.re_static, &dummy_cause, ); } (Some(ty::OutlivesPredicate(t_a, r_b)), _) => { - selcx.infcx.register_region_obligation_with_cause( + selcx.infcx.register_type_outlives_constraint( t_a, r_b, &dummy_cause, diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 8d6e6b4a651..18f28d72f6f 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -188,6 +188,20 @@ where .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } + /// Computes the least-upper-bound, or mutual supertype, of two values. + pub fn lub<T: ToTrace<'tcx>>( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + expected: T, + actual: T, + ) -> Result<T, TypeError<'tcx>> { + self.infcx + .at(cause, param_env) + .lub(expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + #[must_use] pub fn select_where_possible(&self) -> Vec<E> { self.engine.borrow_mut().select_where_possible(self.infcx) diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 34c3c905bd9..951dfb879ae 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -428,7 +428,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => { if infcx.considering_regions { - infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)); + infcx.register_region_outlives_constraint(data, &obligation.cause); } ProcessResult::Changed(Default::default()) @@ -439,7 +439,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { r_b, ))) => { if infcx.considering_regions { - infcx.register_region_obligation_with_cause(t_a, r_b, &obligation.cause); + infcx.register_type_outlives_constraint(t_a, r_b, &obligation.cause); } ProcessResult::Changed(Default::default()) } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 31b075db04b..999ef97683c 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -221,7 +221,7 @@ fn pred_known_to_hold_modulo_regions<'tcx>( if result.must_apply_modulo_regions() { true - } else if result.may_apply() { + } else if result.may_apply() && !infcx.next_trait_solver() { // Sometimes obligations are ambiguous because the recursive evaluator // is not smart enough, so we fall back to fulfillment when we're not certain // that an obligation holds or not. Even still, we must make sure that @@ -340,7 +340,7 @@ pub fn normalize_param_env_or_error<'tcx>( let mut predicates: Vec<_> = util::elaborate( tcx, unnormalized_env.caller_bounds().into_iter().map(|predicate| { - if tcx.features().generic_const_exprs() { + if tcx.features().generic_const_exprs() || tcx.next_trait_solver_globally() { return predicate; } @@ -405,8 +405,6 @@ pub fn normalize_param_env_or_error<'tcx>( // compatibility. Eventually when lazy norm is implemented this can just be removed. // We do not normalize types here as there is no backwards compatibility requirement // for us to do so. - // - // FIXME(-Znext-solver): remove this hack since we have deferred projection equality predicate.fold_with(&mut ConstNormalizer(tcx)) }), ) @@ -542,10 +540,13 @@ pub fn try_evaluate_const<'tcx>( | ty::ConstKind::Placeholder(_) | ty::ConstKind::Expr(_) => Err(EvaluateConstErr::HasGenericsOrInfers), ty::ConstKind::Unevaluated(uv) => { + let opt_anon_const_kind = + (tcx.def_kind(uv.def) == DefKind::AnonConst).then(|| tcx.anon_const_kind(uv.def)); + // Postpone evaluation of constants that depend on generic parameters or // inference variables. // - // We use `TypingMode::PostAnalysis` here which is not *technically* correct + // We use `TypingMode::PostAnalysis` here which is not *technically* correct // to be revealing opaque types here as borrowcheck has not run yet. However, // CTFE itself uses `TypingMode::PostAnalysis` unconditionally even during // typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821). @@ -553,65 +554,95 @@ pub fn try_evaluate_const<'tcx>( // // FIXME: `const_eval_resolve_for_typeck` should probably just modify the env itself // instead of having this logic here - let (args, typing_env) = if tcx.features().generic_const_exprs() - && uv.has_non_region_infer() - { - // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause - // inference variables and generic parameters to show up in `ty::Const` even though the anon const - // does not actually make use of them. We handle this case specially and attempt to evaluate anyway. - match tcx.thir_abstract_const(uv.def) { - Ok(Some(ct)) => { - let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args)); - if let Err(e) = ct.error_reported() { - return Err(EvaluateConstErr::EvaluationFailure(e)); - } else if ct.has_non_region_infer() || ct.has_non_region_param() { - // If the anon const *does* actually use generic parameters or inference variables from - // the generic arguments provided for it, then we should *not* attempt to evaluate it. - return Err(EvaluateConstErr::HasGenericsOrInfers); - } else { - let args = replace_param_and_infer_args_with_placeholder(tcx, uv.args); - let typing_env = infcx - .typing_env(tcx.erase_regions(param_env)) - .with_post_analysis_normalized(tcx); - (args, typing_env) + let (args, typing_env) = match opt_anon_const_kind { + // We handle `generic_const_exprs` separately as reasonable ways of handling constants in the type system + // completely fall apart under `generic_const_exprs` and makes this whole function Really hard to reason + // about if you have to consider gce whatsoever. + Some(ty::AnonConstKind::GCE) => { + if uv.has_non_region_infer() || uv.has_non_region_param() { + // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause + // inference variables and generic parameters to show up in `ty::Const` even though the anon const + // does not actually make use of them. We handle this case specially and attempt to evaluate anyway. + match tcx.thir_abstract_const(uv.def) { + Ok(Some(ct)) => { + let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args)); + if let Err(e) = ct.error_reported() { + return Err(EvaluateConstErr::EvaluationFailure(e)); + } else if ct.has_non_region_infer() || ct.has_non_region_param() { + // If the anon const *does* actually use generic parameters or inference variables from + // the generic arguments provided for it, then we should *not* attempt to evaluate it. + return Err(EvaluateConstErr::HasGenericsOrInfers); + } else { + let args = + replace_param_and_infer_args_with_placeholder(tcx, uv.args); + let typing_env = infcx + .typing_env(tcx.erase_regions(param_env)) + .with_post_analysis_normalized(tcx); + (args, typing_env) + } + } + Err(_) | Ok(None) => { + let args = GenericArgs::identity_for_item(tcx, uv.def); + let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def); + (args, typing_env) + } } + } else { + let typing_env = infcx + .typing_env(tcx.erase_regions(param_env)) + .with_post_analysis_normalized(tcx); + (uv.args, typing_env) } - Err(_) | Ok(None) => { - let args = GenericArgs::identity_for_item(tcx, uv.def); - let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def); - (args, typing_env) + } + Some(ty::AnonConstKind::RepeatExprCount) => { + if uv.has_non_region_infer() { + // Diagnostics will sometimes replace the identity args of anon consts in + // array repeat expr counts with inference variables so we have to handle this + // even though it is not something we should ever actually encounter. + // + // Array repeat expr counts are allowed to syntactically use generic parameters + // but must not actually depend on them in order to evalaute successfully. This means + // that it is actually fine to evalaute them in their own environment rather than with + // the actually provided generic arguments. + tcx.dcx().delayed_bug("AnonConst with infer args but no error reported"); } + + // The generic args of repeat expr counts under `min_const_generics` are not supposed to + // affect evaluation of the constant as this would make it a "truly" generic const arg. + // To prevent this we discard all the generic arguments and evalaute with identity args + // and in its own environment instead of the current environment we are normalizing in. + let args = GenericArgs::identity_for_item(tcx, uv.def); + let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def); + + (args, typing_env) + } + _ => { + // We are only dealing with "truly" generic/uninferred constants here: + // - GCEConsts have been handled separately + // - Repeat expr count back compat consts have also been handled separately + // So we are free to simply defer evaluation here. + // + // FIXME: This assumes that `args` are normalized which is not necessarily true + // + // Const patterns are converted to type system constants before being + // evaluated. However, we don't care about them here as pattern evaluation + // logic does not go through type system normalization. If it did this would + // be a backwards compatibility problem as we do not enforce "syntactic" non- + // usage of generic parameters like we do here. + if uv.args.has_non_region_param() || uv.args.has_non_region_infer() { + return Err(EvaluateConstErr::HasGenericsOrInfers); + } + + let typing_env = infcx + .typing_env(tcx.erase_regions(param_env)) + .with_post_analysis_normalized(tcx); + (uv.args, typing_env) } - } else if tcx.def_kind(uv.def) == DefKind::AnonConst && uv.has_non_region_infer() { - // FIXME: remove this when `const_evaluatable_unchecked` is a hard error. - // - // Diagnostics will sometimes replace the identity args of anon consts in - // array repeat expr counts with inference variables so we have to handle this - // even though it is not something we should ever actually encounter. - // - // Array repeat expr counts are allowed to syntactically use generic parameters - // but must not actually depend on them in order to evalaute successfully. This means - // that it is actually fine to evalaute them in their own environment rather than with - // the actually provided generic arguments. - tcx.dcx().delayed_bug( - "Encountered anon const with inference variable args but no error reported", - ); - - let args = GenericArgs::identity_for_item(tcx, uv.def); - let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def); - (args, typing_env) - } else { - // FIXME: This codepath is reachable under `associated_const_equality` and in the - // future will be reachable by `min_generic_const_args`. We should handle inference - // variables and generic parameters properly instead of doing nothing. - let typing_env = infcx - .typing_env(tcx.erase_regions(param_env)) - .with_post_analysis_normalized(tcx); - (uv.args, typing_env) }; - let uv = ty::UnevaluatedConst::new(uv.def, args); + let uv = ty::UnevaluatedConst::new(uv.def, args); let erased_uv = tcx.erase_regions(uv); + use rustc_middle::mir::interpret::ErrorHandled; match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, DUMMY_SP) { Ok(Ok(val)) => Ok(ty::Const::new_value( diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 88a0c402702..eb6d5c8a60a 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -299,12 +299,21 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { ); } + // We don't replace bound vars in the generic arguments of the free alias with + // placeholders. This doesn't cause any issues as instantiating parameters with + // bound variables is special-cased to rewrite the debruijn index to be higher + // whenever we fold through a binder. + // + // However, we do replace any escaping bound vars in the resulting goals with + // placeholders as the trait solver does not expect to encounter escaping bound + // vars in obligations. + // + // FIXME(lazy_type_alias): Check how much this actually matters for perf before + // stabilization. This is a bit weird and generally not how we handle binders in + // the compiler so ideally we'd do the same boundvar->placeholder->boundvar dance + // that other kinds of normalization do. let infcx = self.selcx.infcx; self.obligations.extend( - // FIXME(BoxyUwU): - // FIXME(lazy_type_alias): - // It seems suspicious to instantiate the predicates with arguments that might be bound vars, - // we might wind up instantiating one of these bound vars underneath a hrtb. infcx.tcx.predicates_of(free.def_id).instantiate_own(infcx.tcx, free.args).map( |(mut predicate, span)| { if free.has_escaping_bound_vars() { diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 68983ef80fa..59d3ac21387 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -9,7 +9,7 @@ use rustc_span::def_id::LocalDefId; use tracing::instrument; use crate::infer::InferCtxt; -use crate::traits::{ObligationCause, ObligationCtxt}; +use crate::traits::ObligationCause; /// Implied bounds are region relationships that we deduce /// automatically. The idea is that (e.g.) a caller must check that a @@ -79,24 +79,9 @@ fn implied_outlives_bounds<'a, 'tcx>( if !constraints.is_empty() { let QueryRegionConstraints { outlives } = constraints; - // Instantiation may have produced new inference variables and constraints on those - // variables. Process these constraints. - let ocx = ObligationCtxt::new(infcx); let cause = ObligationCause::misc(span, body_id); - for &constraint in &outlives { - ocx.register_obligation(infcx.query_outlives_constraint_to_obligation( - constraint, - cause.clone(), - param_env, - )); - } - - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - infcx.dcx().span_bug( - span, - "implied_outlives_bounds failed to solve obligations from instantiation", - ); + for &(predicate, _) in &outlives { + infcx.register_outlives_constraint(predicate, &cause); } }; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index ca58da5ca6d..ed0f34b5aa9 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -378,6 +378,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( term: projected_term, obligations: mut projected_obligations, })) => { + debug!("opt_normalize_projection_type: progress"); // if projection succeeded, then what we get out of this // is also non-normalized (consider: it was derived from // an impl, where-clause etc) and hence we must @@ -408,6 +409,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( Ok(Some(result.value)) } Ok(Projected::NoProgress(projected_ty)) => { + debug!("opt_normalize_projection_type: no progress"); let result = Normalized { value: projected_ty, obligations: PredicateObligations::new() }; infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); @@ -621,8 +623,17 @@ struct Progress<'tcx> { } impl<'tcx> Progress<'tcx> { - fn error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self { - Progress { term: Ty::new_error(tcx, guar).into(), obligations: PredicateObligations::new() } + fn error_for_term( + tcx: TyCtxt<'tcx>, + alias_term: ty::AliasTerm<'tcx>, + guar: ErrorGuaranteed, + ) -> Self { + let err_term = if alias_term.kind(tcx).is_type() { + Ty::new_error(tcx, guar).into() + } else { + ty::Const::new_error(tcx, guar).into() + }; + Progress { term: err_term, obligations: PredicateObligations::new() } } fn with_addl_obligations(mut self, mut obligations: PredicateObligations<'tcx>) -> Self { @@ -650,7 +661,11 @@ fn project<'cx, 'tcx>( } if let Err(guar) = obligation.predicate.error_reported() { - return Ok(Projected::Progress(Progress::error(selcx.tcx(), guar))); + return Ok(Projected::Progress(Progress::error_for_term( + selcx.tcx(), + obligation.predicate, + guar, + ))); } let mut candidates = ProjectionCandidateSet::None; @@ -1965,7 +1980,13 @@ fn confirm_impl_candidate<'cx, 'tcx>( let param_env = obligation.param_env; let assoc_term = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) { Ok(assoc_term) => assoc_term, - Err(guar) => return Ok(Projected::Progress(Progress::error(tcx, guar))), + Err(guar) => { + return Ok(Projected::Progress(Progress::error_for_term( + tcx, + obligation.predicate, + guar, + ))); + } }; // This means that the impl is missing a definition for the diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index d9b57f0c67d..e294f7839aa 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -1,6 +1,6 @@ use std::ops::ControlFlow; -use rustc_infer::infer::RegionObligation; +use rustc_infer::infer::TypeOutlivesConstraint; use rustc_infer::infer::canonical::CanonicalQueryInput; use rustc_infer::traits::query::OutlivesBound; use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds; @@ -141,7 +141,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( && !ocx.infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat && ty.visit_with(&mut ContainsBevyParamSet { tcx: ocx.infcx.tcx }).is_break() { - for RegionObligation { sup_type, sub_region, .. } in + for TypeOutlivesConstraint { sup_type, sub_region, .. } in ocx.infcx.take_registered_region_obligations() { let mut components = smallvec![]; diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 10a2ba049d8..7d869b27445 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -65,71 +65,92 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let def_id = obligation.predicate.def_id(); let tcx = self.tcx(); - if tcx.is_lang_item(def_id, LangItem::Copy) { - debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty()); - - // User-defined copy impls are permitted, but only for - // structs and enums. - self.assemble_candidates_from_impls(obligation, &mut candidates); - - // For other types, we'll use the builtin rules. - let copy_conditions = self.copy_clone_conditions(obligation); - self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates); - } else if tcx.is_lang_item(def_id, LangItem::DiscriminantKind) { - // `DiscriminantKind` is automatically implemented for every type. - candidates.vec.push(BuiltinCandidate { has_nested: false }); - } else if tcx.is_lang_item(def_id, LangItem::PointeeTrait) { - // `Pointee` is automatically implemented for every type. - candidates.vec.push(BuiltinCandidate { has_nested: false }); - } else if tcx.is_lang_item(def_id, LangItem::Sized) { - self.assemble_builtin_sized_candidate(obligation, &mut candidates); - } else if tcx.is_lang_item(def_id, LangItem::Unsize) { - self.assemble_candidates_for_unsizing(obligation, &mut candidates); - } else if tcx.is_lang_item(def_id, LangItem::Destruct) { - self.assemble_const_destruct_candidates(obligation, &mut candidates); - } else if tcx.is_lang_item(def_id, LangItem::TransmuteTrait) { - // User-defined transmutability impls are permitted. - self.assemble_candidates_from_impls(obligation, &mut candidates); - self.assemble_candidates_for_transmutability(obligation, &mut candidates); - } else if tcx.is_lang_item(def_id, LangItem::Tuple) { - self.assemble_candidate_for_tuple(obligation, &mut candidates); - } else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) { - self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates); - } else if tcx.is_lang_item(def_id, LangItem::BikeshedGuaranteedNoDrop) { - self.assemble_candidates_for_bikeshed_guaranteed_no_drop_trait( - obligation, - &mut candidates, - ); - } else { - if tcx.is_lang_item(def_id, LangItem::Clone) { - // Same builtin conditions as `Copy`, i.e., every type which has builtin support - // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone` - // types have builtin support for `Clone`. - let clone_conditions = self.copy_clone_conditions(obligation); - self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates); + let lang_item = tcx.as_lang_item(def_id); + match lang_item { + Some(LangItem::Copy | LangItem::Clone) => { + debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty()); + + // User-defined copy impls are permitted, but only for + // structs and enums. + self.assemble_candidates_from_impls(obligation, &mut candidates); + + // For other types, we'll use the builtin rules. + let copy_conditions = self.copy_clone_conditions(obligation); + self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates); } - - if tcx.is_lang_item(def_id, LangItem::Coroutine) { - self.assemble_coroutine_candidates(obligation, &mut candidates); - } else if tcx.is_lang_item(def_id, LangItem::Future) { - self.assemble_future_candidates(obligation, &mut candidates); - } else if tcx.is_lang_item(def_id, LangItem::Iterator) { - self.assemble_iterator_candidates(obligation, &mut candidates); - } else if tcx.is_lang_item(def_id, LangItem::FusedIterator) { - self.assemble_fused_iterator_candidates(obligation, &mut candidates); - } else if tcx.is_lang_item(def_id, LangItem::AsyncIterator) { - self.assemble_async_iterator_candidates(obligation, &mut candidates); - } else if tcx.is_lang_item(def_id, LangItem::AsyncFnKindHelper) { - self.assemble_async_fn_kind_helper_candidates(obligation, &mut candidates); + Some(LangItem::DiscriminantKind) => { + // `DiscriminantKind` is automatically implemented for every type. + candidates.vec.push(BuiltinCandidate { has_nested: false }); } + Some(LangItem::PointeeTrait) => { + // `Pointee` is automatically implemented for every type. + candidates.vec.push(BuiltinCandidate { has_nested: false }); + } + Some(LangItem::Sized) => { + self.assemble_builtin_sized_candidate(obligation, &mut candidates); + } + Some(LangItem::Unsize) => { + self.assemble_candidates_for_unsizing(obligation, &mut candidates); + } + Some(LangItem::Destruct) => { + self.assemble_const_destruct_candidates(obligation, &mut candidates); + } + Some(LangItem::TransmuteTrait) => { + // User-defined transmutability impls are permitted. + self.assemble_candidates_from_impls(obligation, &mut candidates); + self.assemble_candidates_for_transmutability(obligation, &mut candidates); + } + Some(LangItem::Tuple) => { + self.assemble_candidate_for_tuple(obligation, &mut candidates); + } + Some(LangItem::FnPtrTrait) => { + self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates); + } + Some(LangItem::BikeshedGuaranteedNoDrop) => { + self.assemble_candidates_for_bikeshed_guaranteed_no_drop_trait( + obligation, + &mut candidates, + ); + } + _ => { + // We re-match here for traits that can have both builtin impls and user written impls. + // After the builtin impls we need to also add user written impls, which we do not want to + // do in general because just checking if there are any is expensive. + match lang_item { + Some(LangItem::Coroutine) => { + self.assemble_coroutine_candidates(obligation, &mut candidates); + } + Some(LangItem::Future) => { + self.assemble_future_candidates(obligation, &mut candidates); + } + Some(LangItem::Iterator) => { + self.assemble_iterator_candidates(obligation, &mut candidates); + } + Some(LangItem::FusedIterator) => { + self.assemble_fused_iterator_candidates(obligation, &mut candidates); + } + Some(LangItem::AsyncIterator) => { + self.assemble_async_iterator_candidates(obligation, &mut candidates); + } + Some(LangItem::AsyncFnKindHelper) => { + self.assemble_async_fn_kind_helper_candidates( + obligation, + &mut candidates, + ); + } + Some(LangItem::AsyncFn | LangItem::AsyncFnMut | LangItem::AsyncFnOnce) => { + self.assemble_async_closure_candidates(obligation, &mut candidates); + } + Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce) => { + self.assemble_closure_candidates(obligation, &mut candidates); + self.assemble_fn_pointer_candidates(obligation, &mut candidates); + } + _ => {} + } - // FIXME: Put these into `else if` blocks above, since they're built-in. - self.assemble_closure_candidates(obligation, &mut candidates); - self.assemble_async_closure_candidates(obligation, &mut candidates); - self.assemble_fn_pointer_candidates(obligation, &mut candidates); - - self.assemble_candidates_from_impls(obligation, &mut candidates); - self.assemble_candidates_from_object_ty(obligation, &mut candidates); + self.assemble_candidates_from_impls(obligation, &mut candidates); + self.assemble_candidates_from_object_ty(obligation, &mut candidates); + } } self.assemble_candidates_from_projected_tys(obligation, &mut candidates); @@ -360,9 +381,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PolyTraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - let Some(kind) = self.tcx().fn_trait_kind_from_def_id(obligation.predicate.def_id()) else { - return; - }; + let kind = self.tcx().fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap(); // Okay to skip binder because the args on closure types never // touch bound regions, they just capture the in-scope @@ -424,11 +443,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PolyTraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - let Some(goal_kind) = - self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()) - else { - return; - }; + let goal_kind = + self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap(); match *obligation.self_ty().skip_binder().kind() { ty::CoroutineClosure(_, args) => { @@ -501,11 +517,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PolyTraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - // We provide impl of all fn traits for fn pointers. - if !self.tcx().is_fn_trait(obligation.predicate.def_id()) { - return; - } - // Keep this function in sync with extract_tupled_inputs_and_output_from_callable // until the old solver (and thus this function) is removed. diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 94190cd3ae3..c9169127e0b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -251,16 +251,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); let obligations = if has_nested { let trait_def = obligation.predicate.def_id(); - let conditions = if tcx.is_lang_item(trait_def, LangItem::Sized) { - self.sized_conditions(obligation) - } else if tcx.is_lang_item(trait_def, LangItem::Copy) { - self.copy_clone_conditions(obligation) - } else if tcx.is_lang_item(trait_def, LangItem::Clone) { - self.copy_clone_conditions(obligation) - } else if tcx.is_lang_item(trait_def, LangItem::FusedIterator) { - self.fused_iterator_conditions(obligation) - } else { - bug!("unexpected builtin trait {:?}", trait_def) + let conditions = match tcx.as_lang_item(trait_def) { + Some(LangItem::Sized) => self.sized_conditions(obligation), + Some(LangItem::Copy | LangItem::Clone) => self.copy_clone_conditions(obligation), + Some(LangItem::FusedIterator) => self.fused_iterator_conditions(obligation), + other => bug!("unexpected builtin trait {trait_def:?} ({other:?})"), }; let BuiltinImplConditions::Where(types) = conditions else { bug!("obligation {:?} had matched a builtin impl but now doesn't", obligation); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 44a76f6e083..3a2f9e8ca17 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -265,9 +265,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, ) -> SelectionResult<'tcx, Selection<'tcx>> { - if self.infcx.next_trait_solver() { - return self.infcx.select_in_new_trait_solver(obligation); - } + assert!(!self.infcx.next_trait_solver()); let candidate = match self.select_from_obligation(obligation) { Err(SelectionError::Overflow(OverflowError::Canonical)) => { @@ -299,6 +297,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, ) -> SelectionResult<'tcx, Selection<'tcx>> { + if self.infcx.next_trait_solver() { + return self.infcx.select_in_new_trait_solver(obligation); + } + self.poly_select(&Obligation { cause: obligation.cause.clone(), param_env: obligation.param_env, @@ -1782,7 +1784,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if !generics.is_own_empty() && obligation.predicate.args[generics.parent_count..].iter().any(|&p| { p.has_non_region_infer() - && match p.unpack() { + && match p.kind() { ty::GenericArgKind::Const(ct) => { self.infcx.shallow_resolve_const(ct) != ct } @@ -2866,7 +2868,7 @@ fn rebind_coroutine_witness_types<'tcx>( let shifted_coroutine_types = tcx.shift_bound_var_indices(bound_vars.len(), bound_coroutine_types.skip_binder()); ty::Binder::bind_with_vars( - ty::EarlyBinder::bind(shifted_coroutine_types.to_vec()).instantiate(tcx, args), + ty::EarlyBinder::bind(shifted_coroutine_types.types.to_vec()).instantiate(tcx, args), tcx.mk_bound_variable_kinds_from_iter( bound_vars.iter().chain(bound_coroutine_types.bound_vars()), ), diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index e6d5d336b8d..3f741345404 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -39,7 +39,7 @@ impl<'tcx> At<'_, 'tcx> { return Ok(term); } - let new_infer = match term.unpack() { + let new_infer = match term.kind() { ty::TermKind::Ty(_) => self.infcx.next_ty_var(self.cause.span).into(), ty::TermKind::Const(_) => self.infcx.next_const_var(self.cause.span).into(), }; diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 08d3b92e9b5..3018dad8e09 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -37,7 +37,7 @@ pub fn obligations<'tcx>( span: Span, ) -> Option<PredicateObligations<'tcx>> { // Handle the "cycle" case (see comment above) by bailing out if necessary. - let term = match term.unpack() { + let term = match term.kind() { TermKind::Ty(ty) => { match ty.kind() { ty::Infer(ty::TyVar(_)) => { |
