diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src')
41 files changed, 1172 insertions, 880 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 2c16672d786..b9acadc406e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -51,6 +51,7 @@ use std::path::PathBuf; use std::{cmp, fmt, iter}; use rustc_abi::ExternAbi; +use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ Applicability, Diag, DiagStyledString, IntoDiagArg, MultiSpan, StringPart, pluralize, @@ -73,7 +74,7 @@ use rustc_middle::ty::{ TypeVisitableExt, }; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, sym}; +use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, Symbol, sym}; use tracing::{debug, instrument}; use crate::error_reporting::TypeErrCtxt; @@ -82,9 +83,7 @@ use crate::infer; use crate::infer::relate::{self, RelateResult, TypeRelation}; use crate::infer::{InferCtxt, InferCtxtExt as _, TypeTrace, ValuePairs}; use crate::solve::deeply_normalize_for_diagnostics; -use crate::traits::{ - IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, -}; +use crate::traits::{MatchExpressionArmCause, ObligationCause, ObligationCauseCode}; mod note_and_explain; mod suggest; @@ -227,7 +226,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { struct AbsolutePathPrinter<'tcx> { tcx: TyCtxt<'tcx>, - segments: Vec<String>, + segments: Vec<Symbol>, } impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { @@ -255,7 +254,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { - self.segments = vec![self.tcx.crate_name(cnum).to_string()]; + self.segments = vec![self.tcx.crate_name(cnum)]; Ok(()) } fn path_qualified( @@ -281,7 +280,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { disambiguated_data: &DisambiguatedDefPathData, ) -> Result<(), PrintError> { print_prefix(self)?; - self.segments.push(disambiguated_data.to_string()); + self.segments.push(disambiguated_data.as_sym(true)); Ok(()) } fn path_generic_args( @@ -316,7 +315,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // known" by the same name, we use the "absolute path" which uses the original // crate name instead. let (expected, found) = if expected_str == found_str { - (expected_abs.join("::"), found_abs.join("::")) + (join_path_syms(&expected_abs), join_path_syms(&found_abs)) } else { (expected_str.clone(), found_str.clone()) }; @@ -613,18 +612,28 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } }, - ObligationCauseCode::IfExpression(box IfExpressionCause { - then_id, - else_id, - then_ty, - else_ty, - outer_span, - .. - }) => { - let then_span = self.find_block_span_from_hir_id(then_id); - let else_span = self.find_block_span_from_hir_id(else_id); - if let hir::Node::Expr(e) = self.tcx.hir_node(else_id) - && let hir::ExprKind::If(_cond, _then, None) = e.kind + ObligationCauseCode::IfExpression { expr_id, .. } => { + let hir::Node::Expr(&hir::Expr { + kind: hir::ExprKind::If(cond_expr, then_expr, Some(else_expr)), + span: expr_span, + .. + }) = self.tcx.hir_node(expr_id) + else { + return; + }; + let then_span = self.find_block_span_from_hir_id(then_expr.hir_id); + let then_ty = self + .typeck_results + .as_ref() + .expect("if expression only expected inside FnCtxt") + .expr_ty(then_expr); + let else_span = self.find_block_span_from_hir_id(else_expr.hir_id); + let else_ty = self + .typeck_results + .as_ref() + .expect("if expression only expected inside FnCtxt") + .expr_ty(else_expr); + if let hir::ExprKind::If(_cond, _then, None) = else_expr.kind && else_ty.is_unit() { // Account for `let x = if a { 1 } else if b { 2 };` @@ -632,9 +641,32 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.note("consider adding an `else` block that evaluates to the expected type"); } err.span_label(then_span, "expected because of this"); + + let outer_span = if self.tcx.sess.source_map().is_multiline(expr_span) { + if then_span.hi() == expr_span.hi() || else_span.hi() == expr_span.hi() { + // Point at condition only if either block has the same end point as + // the whole expression, since that'll cause awkward overlapping spans. + Some(expr_span.shrink_to_lo().to(cond_expr.peel_drop_temps().span)) + } else { + Some(expr_span) + } + } else { + None + }; if let Some(sp) = outer_span { err.span_label(sp, "`if` and `else` have incompatible types"); } + + let then_id = if let hir::ExprKind::Block(then_blk, _) = then_expr.kind { + then_blk.hir_id + } else { + then_expr.hir_id + }; + let else_id = if let hir::ExprKind::Block(else_blk, _) = else_expr.kind { + else_blk.hir_id + } else { + else_expr.hir_id + }; if let Some(subdiag) = self.suggest_remove_semi_or_return_binding( Some(then_id), then_ty, 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 bfef3340b32..1db05ced8d2 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 @@ -909,11 +909,11 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { } } (GenericArgKind::Const(inner_ct), TermKind::Const(target_ct)) => { - use ty::InferConst::*; match (inner_ct.kind(), target_ct.kind()) { - (ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => { - self.tecx.root_const_var(a_vid) == self.tecx.root_const_var(b_vid) - } + ( + ty::ConstKind::Infer(ty::InferConst::Var(a_vid)), + ty::ConstKind::Infer(ty::InferConst::Var(b_vid)), + ) => self.tecx.root_const_var(a_vid) == self.tecx.root_const_var(b_vid), _ => false, } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs index 139b2997136..8fe4ffebd86 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs @@ -75,7 +75,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result { match arg.kind { - hir::TyKind::BareFn(_) => { + hir::TyKind::FnPtr(_) => { self.current_index.shift_in(1); let _ = intravisit::walk_ty(self, arg); self.current_index.shift_out(1); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs index e456ba0eda5..c0b4bdab849 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs @@ -5,7 +5,6 @@ use rustc_span::Span; use crate::error_reporting::TypeErrCtxt; use crate::infer::RegionResolutionError; -use crate::infer::RegionResolutionError::*; mod different_lifetimes; pub mod find_anon_type; @@ -83,8 +82,10 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { pub(super) fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> { match (&self.error, self.regions) { - (Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), *sub, *sup)), - (Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => { + (Some(RegionResolutionError::ConcreteFailure(origin, sub, sup)), None) => { + Some((origin.span(), *sub, *sup)) + } + (Some(RegionResolutionError::SubSupConflict(_, _, origin, sub, _, sup, _)), None) => { Some((origin.span(), *sub, *sup)) } (None, Some((span, sub, sup))) => Some((span, sub, sup)), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs index aa7935a29f0..73a04d78519 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs @@ -2,8 +2,6 @@ //! where one region is named and the other is anonymous. use rustc_errors::Diag; -use rustc_middle::ty; -use rustc_span::kw; use tracing::debug; use crate::error_reporting::infer::nice_region_error::NiceRegionError; @@ -27,12 +25,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // only introduced anonymous regions in parameters) as well as a // version new_ty of its type where the anonymous region is replaced // with the named one. - let (named, anon, anon_param_info, region_info) = if sub.has_name() + let (named, anon, anon_param_info, region_info) = if sub.is_named(self.tcx()) && let Some(region_info) = self.tcx().is_suitable_region(self.generic_param_scope, sup) && let Some(anon_param_info) = self.find_param_with_region(sup, sub) { (sub, sup, anon_param_info, region_info) - } else if sup.has_name() + } else if sup.is_named(self.tcx()) && let Some(region_info) = self.tcx().is_suitable_region(self.generic_param_scope, sub) && let Some(anon_param_info) = self.find_param_with_region(sub, sup) { @@ -58,14 +56,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let scope_def_id = region_info.scope; let is_impl_item = region_info.is_impl_item; - match anon_param_info.kind { - ty::LateParamRegionKind::Named(_, kw::UnderscoreLifetime) - | ty::LateParamRegionKind::Anon(_) => {} - _ => { - /* not an anonymous region */ - debug!("try_report_named_anon_conflict: not an anonymous region"); - return None; - } + if anon_param_info.kind.is_named(self.tcx()) { + /* not an anonymous region */ + debug!("try_report_named_anon_conflict: not an anonymous region"); + return None; } if is_impl_item { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index 5056161e117..64fc365c44a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -164,7 +164,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { sub_region @ Region(Interned(RePlaceholder(_), _)), sup_region, )) => self.try_report_trait_placeholder_mismatch( - (!sup_region.has_name()).then_some(*sup_region), + (!sup_region.is_named(self.tcx())).then_some(*sup_region), cause, Some(*sub_region), None, @@ -176,7 +176,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { sub_region, sup_region @ Region(Interned(RePlaceholder(_), _)), )) => self.try_report_trait_placeholder_mismatch( - (!sub_region.has_name()).then_some(*sub_region), + (!sub_region.is_named(self.tcx())).then_some(*sub_region), cause, None, Some(*sup_region), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs index 7fcd3c847e3..3bab09bc587 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs @@ -1,5 +1,6 @@ use rustc_data_structures::intern::Interned; use rustc_errors::Diag; +use rustc_middle::bug; use rustc_middle::ty::{self, RePlaceholder, Region}; use crate::error_reporting::infer::nice_region_error::NiceRegionError; @@ -28,20 +29,22 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { )), )) => { let span = *span; - let (sub_span, sub_symbol) = match sub_name { - ty::BoundRegionKind::Named(def_id, symbol) => { - (Some(self.tcx().def_span(def_id)), Some(symbol)) + let (sub_span, sub_symbol) = match *sub_name { + ty::BoundRegionKind::Named(def_id) => { + (Some(self.tcx().def_span(def_id)), Some(self.tcx().item_name(def_id))) } ty::BoundRegionKind::Anon | ty::BoundRegionKind::ClosureEnv => (None, None), + ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"), }; - let (sup_span, sup_symbol) = match sup_name { - ty::BoundRegionKind::Named(def_id, symbol) => { - (Some(self.tcx().def_span(def_id)), Some(symbol)) + let (sup_span, sup_symbol) = match *sup_name { + ty::BoundRegionKind::Named(def_id) => { + (Some(self.tcx().def_span(def_id)), Some(self.tcx().item_name(def_id))) } ty::BoundRegionKind::Anon | ty::BoundRegionKind::ClosureEnv => (None, None), + ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"), }; let diag = match (sub_span, sup_span, sub_symbol, sup_symbol) { - (Some(sub_span), Some(sup_span), Some(&sub_symbol), Some(&sup_symbol)) => { + (Some(sub_span), Some(sup_span), Some(sub_symbol), Some(sup_symbol)) => { PlaceholderRelationLfNotSatisfied::HasBoth { span, sub_span, @@ -51,7 +54,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { note: (), } } - (Some(sub_span), Some(sup_span), _, Some(&sup_symbol)) => { + (Some(sub_span), Some(sup_span), _, Some(sup_symbol)) => { PlaceholderRelationLfNotSatisfied::HasSup { span, sub_span, @@ -60,7 +63,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { note: (), } } - (Some(sub_span), Some(sup_span), Some(&sub_symbol), _) => { + (Some(sub_span), Some(sup_span), Some(sub_symbol), _) => { PlaceholderRelationLfNotSatisfied::HasSub { span, sub_span, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index eaa06d8e8b0..3edc365c886 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -45,7 +45,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let return_sp = sub_origin.span(); let param = self.find_param_with_region(*sup_r, *sub_r)?; let simple_ident = param.param.pat.simple_ident(); - let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() }; + let lifetime_name = + if sup_r.is_named(self.tcx()) { sup_r.to_string() } else { "'_".to_owned() }; let (mention_influencer, influencer_point) = if sup_origin.span().overlaps(param.param_ty_span) { @@ -99,7 +100,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // We don't need a note, it's already at the end, it can be shown as a `span_label`. require_span_as_label: (!require_as_note).then_some(require_span), - has_lifetime: sup_r.has_name(), + has_lifetime: sup_r.is_named(self.tcx()), lifetime: lifetime_name.clone(), has_param_name: simple_ident.is_some(), param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs index b66bd2c6ab7..772a7f01332 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs @@ -5,6 +5,7 @@ use rustc_hir::def::{Namespace, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{Visitor, walk_ty}; use rustc_hir::{self as hir, AmbigArg}; +use rustc_infer::infer::SubregionOrigin; use rustc_middle::hir::nested_filter; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::ExpectedFound; @@ -16,7 +17,7 @@ use tracing::debug; use crate::error_reporting::infer::nice_region_error::NiceRegionError; use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlighted; use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff}; -use crate::infer::{RegionResolutionError, Subtype, ValuePairs}; +use crate::infer::{RegionResolutionError, ValuePairs}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`. @@ -32,7 +33,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { _sup, _, ) = error.clone() - && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin) + && let (SubregionOrigin::Subtype(sup_trace), SubregionOrigin::Subtype(sub_trace)) = + (&sup_origin, &sub_origin) && let &ObligationCauseCode::CompareImplItem { trait_item_def_id, .. } = sub_trace.cause.code() && sub_trace.values == sup_trace.values @@ -58,14 +60,15 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // Mark all unnamed regions in the type with a number. // This diagnostic is called in response to lifetime errors, so be informative. struct HighlightBuilder<'tcx> { + tcx: TyCtxt<'tcx>, highlight: RegionHighlightMode<'tcx>, counter: usize, } impl<'tcx> HighlightBuilder<'tcx> { - fn build(sig: ty::PolyFnSig<'tcx>) -> RegionHighlightMode<'tcx> { + fn build(tcx: TyCtxt<'tcx>, sig: ty::PolyFnSig<'tcx>) -> RegionHighlightMode<'tcx> { let mut builder = - HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1 }; + HighlightBuilder { tcx, highlight: RegionHighlightMode::default(), counter: 1 }; sig.visit_with(&mut builder); builder.highlight } @@ -73,15 +76,15 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for HighlightBuilder<'tcx> { fn visit_region(&mut self, r: ty::Region<'tcx>) { - if !r.has_name() && self.counter <= 3 { + if !r.is_named(self.tcx) && self.counter <= 3 { self.highlight.highlighting_region(r, self.counter); self.counter += 1; } } } - let expected_highlight = HighlightBuilder::build(expected); let tcx = self.cx.tcx; + let expected_highlight = HighlightBuilder::build(tcx, expected); let expected = Highlighted { highlight: expected_highlight, ns: Namespace::TypeNS, @@ -89,7 +92,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { value: expected, } .to_string(); - let found_highlight = HighlightBuilder::build(found); + let found_highlight = HighlightBuilder::build(tcx, found); let found = Highlighted { highlight: found_highlight, ns: Namespace::TypeNS, tcx, value: found } .to_string(); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs index 4a71ab4e06a..5f2aab38c31 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs @@ -46,7 +46,7 @@ pub fn find_param_with_region<'tcx>( ty::ReLateParam(late_param) => (late_param.scope, late_param.kind), ty::ReEarlyParam(ebr) => { let region_def = tcx.generics_of(generic_param_scope).region_param(ebr, tcx).def_id; - (tcx.parent(region_def), ty::LateParamRegionKind::Named(region_def, ebr.name)) + (tcx.parent(region_def), ty::LateParamRegionKind::Named(region_def)) } _ => return None, // not a free region }; @@ -144,7 +144,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // We are only checking is any region meets the condition so order doesn't matter #[allow(rustc::potential_query_instability)] late_bound_regions.iter().any(|r| match *r { - ty::BoundRegionKind::Named(def_id, _) => def_id == region_def_id, + ty::BoundRegionKind::Named(def_id) => def_id == region_def_id, _ => false, }) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index be508c8cee1..db35c988bf7 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -1,3 +1,4 @@ +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{Diag, MultiSpan, pluralize}; use rustc_hir as hir; @@ -8,7 +9,7 @@ use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::print::{FmtPrinter, Printer}; use rustc_middle::ty::{self, Ty, suggest_constraining_type_param}; use rustc_span::def_id::DefId; -use rustc_span::{BytePos, Span, Symbol, sym}; +use rustc_span::{BytePos, Span, Symbol}; use tracing::debug; use crate::error_reporting::TypeErrCtxt; @@ -353,26 +354,6 @@ impl<T> Trait<T> for X { )); } } - (ty::Dynamic(t, _, ty::DynKind::DynStar), _) - if let Some(def_id) = t.principal_def_id() => - { - let mut has_matching_impl = false; - tcx.for_each_relevant_impl(def_id, values.found, |did| { - if DeepRejectCtxt::relate_rigid_infer(tcx) - .types_may_unify(values.found, tcx.type_of(did).skip_binder()) - { - has_matching_impl = true; - } - }); - if has_matching_impl { - let trait_name = tcx.item_name(def_id); - diag.help(format!( - "`{}` implements `{trait_name}`, `#[feature(dyn_star)]` is likely \ - not enabled; that feature it is currently incomplete", - values.found, - )); - } - } (_, ty::Alias(ty::Opaque, opaque_ty)) | (ty::Alias(ty::Opaque, opaque_ty), _) => { if opaque_ty.def_id.is_local() @@ -420,19 +401,33 @@ impl<T> Trait<T> for X { } // If two if arms can be coerced to a trait object, provide a structured // suggestion. - let ObligationCauseCode::IfExpression(cause) = cause.code() else { + let ObligationCauseCode::IfExpression { expr_id, .. } = cause.code() else { return; }; - let hir::Node::Block(blk) = self.tcx.hir_node(cause.then_id) else { - return; - }; - let Some(then) = blk.expr else { - return; - }; - let hir::Node::Block(blk) = self.tcx.hir_node(cause.else_id) else { - return; - }; - let Some(else_) = blk.expr else { + let hir::Node::Expr(&hir::Expr { + kind: + hir::ExprKind::If( + _, + &hir::Expr { + kind: + hir::ExprKind::Block( + &hir::Block { expr: Some(then), .. }, + _, + ), + .. + }, + Some(&hir::Expr { + kind: + hir::ExprKind::Block( + &hir::Block { expr: Some(else_), .. }, + _, + ), + .. + }), + ), + .. + }) = self.tcx.hir_node(*expr_id) + else { return; }; let expected = match values.found.kind() { @@ -486,8 +481,10 @@ impl<T> Trait<T> for X { } } (ty::Adt(_, _), ty::Adt(def, args)) - if let ObligationCauseCode::IfExpression(cause) = cause.code() - && let hir::Node::Block(blk) = self.tcx.hir_node(cause.then_id) + if let ObligationCauseCode::IfExpression { expr_id, .. } = cause.code() + && let hir::Node::Expr(if_expr) = self.tcx.hir_node(*expr_id) + && let hir::ExprKind::If(_, then_expr, _) = if_expr.kind + && let hir::ExprKind::Block(blk, _) = then_expr.kind && let Some(then) = blk.expr && def.is_box() && let boxed_ty = args.type_at(0) @@ -539,8 +536,7 @@ impl<T> Trait<T> for X { } } TypeError::TargetFeatureCast(def_id) => { - let target_spans = - tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span()); + let target_spans = find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TargetFeature(.., span) => *span); diag.note( "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" ); @@ -845,54 +841,32 @@ fn foo(&self) -> Self::T { String::new() } let param_env = tcx.param_env(body_owner_def_id); - match item { - hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. }) => { - // FIXME: account for `#![feature(specialization)]` - for item in &items[..] { - match item.kind { - hir::AssocItemKind::Type => { - // FIXME: account for returning some type in a trait fn impl that has - // an assoc type as a return type (#72076). - if let hir::Defaultness::Default { has_value: true } = - tcx.defaultness(item.id.owner_id) - { - let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity(); - if self.infcx.can_eq(param_env, assoc_ty, found) { - diag.span_label( - item.span, - "associated type defaults can't be assumed inside the \ - trait defining them", - ); - return true; - } - } + if let DefKind::Trait | DefKind::Impl { .. } = tcx.def_kind(parent_id) { + let assoc_items = tcx.associated_items(parent_id); + // FIXME: account for `#![feature(specialization)]` + for assoc_item in assoc_items.in_definition_order() { + if assoc_item.is_type() + // FIXME: account for returning some type in a trait fn impl that has + // an assoc type as a return type (#72076). + && let hir::Defaultness::Default { has_value: true } = assoc_item.defaultness(tcx) + && let assoc_ty = tcx.type_of(assoc_item.def_id).instantiate_identity() + && self.infcx.can_eq(param_env, assoc_ty, found) + { + let msg = match assoc_item.container { + ty::AssocItemContainer::Trait => { + "associated type defaults can't be assumed inside the \ + trait defining them" } - _ => {} - } - } - } - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { items, .. }), - .. - }) => { - for item in &items[..] { - if let hir::AssocItemKind::Type = item.kind { - let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity(); - if let hir::Defaultness::Default { has_value: true } = - tcx.defaultness(item.id.owner_id) - && self.infcx.can_eq(param_env, assoc_ty, found) - { - diag.span_label( - item.span, - "associated type is `default` and may be overridden", - ); - return true; + ty::AssocItemContainer::Impl => { + "associated type is `default` and may be overridden" } - } + }; + diag.span_label(tcx.def_span(assoc_item.def_id), msg); + return true; } } - _ => {} } + false } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 5c669678ccc..f3441a8d72a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -27,7 +27,10 @@ use crate::errors::{ }; use crate::fluent_generated as fluent; use crate::infer::region_constraints::GenericKind; -use crate::infer::{self, InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin}; +use crate::infer::{ + BoundRegionConversionTime, InferCtxt, RegionResolutionError, RegionVariableOrigin, + SubregionOrigin, +}; impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub fn report_region_errors( @@ -219,21 +222,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) { match *origin { - infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { + SubregionOrigin::Subtype(ref trace) => RegionOriginNote::WithRequirement { span: trace.cause.span, requirement: ObligationCauseAsDiagArg(trace.cause.clone()), expected_found: self.values_str(trace.values, &trace.cause, err.long_ty_path()), } .add_to_diag(err), - infer::Reborrow(span) => { + SubregionOrigin::Reborrow(span) => { RegionOriginNote::Plain { span, msg: fluent::trait_selection_reborrow } .add_to_diag(err) } - infer::RelateObjectBound(span) => { + SubregionOrigin::RelateObjectBound(span) => { RegionOriginNote::Plain { span, msg: fluent::trait_selection_relate_object_bound } .add_to_diag(err); } - infer::ReferenceOutlivesReferent(ty, span) => { + SubregionOrigin::ReferenceOutlivesReferent(ty, span) => { RegionOriginNote::WithName { span, msg: fluent::trait_selection_reference_outlives_referent, @@ -242,7 +245,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } .add_to_diag(err); } - infer::RelateParamBound(span, ty, opt_span) => { + SubregionOrigin::RelateParamBound(span, ty, opt_span) => { RegionOriginNote::WithName { span, msg: fluent::trait_selection_relate_param_bound, @@ -258,24 +261,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .add_to_diag(err); } } - infer::RelateRegionParamBound(span, _) => { + SubregionOrigin::RelateRegionParamBound(span, _) => { RegionOriginNote::Plain { span, msg: fluent::trait_selection_relate_region_param_bound, } .add_to_diag(err); } - infer::CompareImplItemObligation { span, .. } => { + SubregionOrigin::CompareImplItemObligation { span, .. } => { RegionOriginNote::Plain { span, msg: fluent::trait_selection_compare_impl_item_obligation, } .add_to_diag(err); } - infer::CheckAssociatedTypeBounds { ref parent, .. } => { + SubregionOrigin::CheckAssociatedTypeBounds { ref parent, .. } => { self.note_region_origin(err, parent); } - infer::AscribeUserTypeProvePredicate(span) => { + SubregionOrigin::AscribeUserTypeProvePredicate(span) => { RegionOriginNote::Plain { span, msg: fluent::trait_selection_ascribe_user_type_prove_predicate, @@ -293,7 +296,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { sup: Region<'tcx>, ) -> Diag<'a> { let mut err = match origin { - infer::Subtype(box trace) => { + SubregionOrigin::Subtype(box trace) => { let terr = TypeError::RegionsDoesNotOutlive(sup, sub); let mut err = self.report_and_explain_type_error( trace, @@ -347,7 +350,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } err } - infer::Reborrow(span) => { + SubregionOrigin::Reborrow(span) => { let reference_valid = note_and_explain::RegionExplanation::new( self.tcx, generic_param_scope, @@ -369,7 +372,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { notes: reference_valid.into_iter().chain(content_valid).collect(), }) } - infer::RelateObjectBound(span) => { + SubregionOrigin::RelateObjectBound(span) => { let object_valid = note_and_explain::RegionExplanation::new( self.tcx, generic_param_scope, @@ -391,7 +394,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { notes: object_valid.into_iter().chain(pointer_valid).collect(), }) } - infer::RelateParamBound(span, ty, opt_span) => { + SubregionOrigin::RelateParamBound(span, ty, opt_span) => { let prefix = match sub.kind() { ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy, _ => note_and_explain::PrefixKind::TypeOutlive, @@ -415,7 +418,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { note, }) } - infer::RelateRegionParamBound(span, ty) => { + SubregionOrigin::RelateRegionParamBound(span, ty) => { let param_instantiated = note_and_explain::RegionExplanation::new( self.tcx, generic_param_scope, @@ -457,7 +460,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { notes: param_instantiated.into_iter().chain(param_must_outlive).collect(), }) } - infer::ReferenceOutlivesReferent(ty, span) => { + SubregionOrigin::ReferenceOutlivesReferent(ty, span) => { let pointer_valid = note_and_explain::RegionExplanation::new( self.tcx, generic_param_scope, @@ -480,7 +483,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { notes: pointer_valid.into_iter().chain(data_valid).collect(), }) } - infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => { + SubregionOrigin::CompareImplItemObligation { + span, + impl_item_def_id, + trait_item_def_id, + } => { let mut err = self.report_extra_impl_obligation( span, impl_item_def_id, @@ -499,7 +506,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } err } - infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => { + SubregionOrigin::CheckAssociatedTypeBounds { + impl_item_def_id, + trait_item_def_id, + parent, + } => { let mut err = self.report_concrete_failure(generic_param_scope, *parent, sub, sup); // Don't mention the item name if it's an RPITIT, since that'll just confuse @@ -520,7 +531,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); err } - infer::AscribeUserTypeProvePredicate(span) => { + SubregionOrigin::AscribeUserTypeProvePredicate(span) => { let instantiated = note_and_explain::RegionExplanation::new( self.tcx, generic_param_scope, @@ -618,7 +629,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // I can't think how to do better than this right now. -nikomatsakis debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure"); match placeholder_origin { - infer::Subtype(box ref trace) + SubregionOrigin::Subtype(box ref trace) if matches!( &trace.cause.code().peel_derives(), ObligationCauseCode::WhereClause(..) @@ -648,7 +659,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) } } - infer::Subtype(box trace) => { + SubregionOrigin::Subtype(box trace) => { let terr = TypeError::RegionsPlaceholderMismatch; return self.report_and_explain_type_error( trace, @@ -702,14 +713,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } let labeled_user_string = match bound_kind { - GenericKind::Param(ref p) => format!("the parameter type `{p}`"), - GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"), - GenericKind::Alias(ref p) => match p.kind(self.tcx) { + GenericKind::Param(_) => format!("the parameter type `{bound_kind}`"), + GenericKind::Placeholder(_) => format!("the placeholder type `{bound_kind}`"), + GenericKind::Alias(p) => match p.kind(self.tcx) { ty::Projection | ty::Inherent => { - format!("the associated type `{p}`") + format!("the associated type `{bound_kind}`") } - ty::Free => format!("the type alias `{p}`"), - ty::Opaque => format!("the opaque type `{p}`"), + ty::Free => format!("the type alias `{bound_kind}`"), + ty::Opaque => format!("the opaque type `{bound_kind}`"), }, }; @@ -718,7 +729,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .dcx() .struct_span_err(span, format!("{labeled_user_string} may not live long enough")); err.code(match sub.kind() { - ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => E0309, + ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.is_named(self.tcx) => E0309, ty::ReStatic => E0310, _ => E0311, }); @@ -744,7 +755,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { || (bound_kind, sub).has_placeholders() || !bound_kind.is_suggestable(self.tcx, false) { - let lt_name = sub.get_name_or_anon().to_string(); + let lt_name = sub.get_name_or_anon(self.tcx).to_string(); err.help(format!("{msg} `{bound_kind}: {lt_name}`...")); break 'suggestion; } @@ -864,13 +875,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - let (lifetime_def_id, lifetime_scope) = match self - .tcx - .is_suitable_region(generic_param_scope, lifetime) - { - Some(info) if !lifetime.has_name() => (info.region_def_id.expect_local(), info.scope), - _ => return lifetime.get_name_or_anon().to_string(), - }; + let (lifetime_def_id, lifetime_scope) = + match self.tcx.is_suitable_region(generic_param_scope, lifetime) { + Some(info) if !lifetime.is_named(self.tcx) => { + (info.region_def_id.expect_local(), info.scope) + } + _ => return lifetime.get_name_or_anon(self.tcx).to_string(), + }; let new_lt = { let generics = self.tcx.generics_of(lifetime_scope); @@ -884,7 +895,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // consider late-bound lifetimes ... used_names.extend(self.tcx.late_bound_vars(hir_id).into_iter().filter_map( |p| match p { - ty::BoundVariableKind::Region(lt) => lt.get_name(), + ty::BoundVariableKind::Region(lt) => lt.get_name(self.tcx), _ => None, }, )); @@ -945,8 +956,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { debug!("report_sub_sup_conflict: sup_region={:?}", sup_region); debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin); - if let infer::Subtype(ref sup_trace) = sup_origin - && let infer::Subtype(ref sub_trace) = sub_origin + if let SubregionOrigin::Subtype(ref sup_trace) = sup_origin + && let SubregionOrigin::Subtype(ref sub_trace) = sub_origin && let Some((sup_expected, sup_found)) = self.values_str(sup_trace.values, &sup_trace.cause, err.long_ty_path()) && let Some((sub_expected, sub_found)) = @@ -995,7 +1006,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> Diag<'_> { let br_string = |br: ty::BoundRegionKind| { let mut s = match br { - ty::BoundRegionKind::Named(_, name) => name.to_string(), + ty::BoundRegionKind::Named(def_id) => self.tcx.item_name(def_id).to_string(), _ => String::new(), }; if !s.is_empty() { @@ -1004,30 +1015,38 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { s }; let var_description = match var_origin { - infer::MiscVariable(_) => String::new(), - infer::PatternRegion(_) => " for pattern".to_string(), - infer::BorrowRegion(_) => " for borrow expression".to_string(), - infer::Autoref(_) => " for autoref".to_string(), - infer::Coercion(_) => " for automatic coercion".to_string(), - infer::BoundRegion(_, br, infer::FnCall) => { + RegionVariableOrigin::Misc(_) => String::new(), + RegionVariableOrigin::PatternRegion(_) => " for pattern".to_string(), + RegionVariableOrigin::BorrowRegion(_) => " for borrow expression".to_string(), + RegionVariableOrigin::Autoref(_) => " for autoref".to_string(), + RegionVariableOrigin::Coercion(_) => " for automatic coercion".to_string(), + RegionVariableOrigin::BoundRegion(_, br, BoundRegionConversionTime::FnCall) => { format!(" for lifetime parameter {}in function call", br_string(br)) } - infer::BoundRegion(_, br, infer::HigherRankedType) => { + RegionVariableOrigin::BoundRegion( + _, + br, + BoundRegionConversionTime::HigherRankedType, + ) => { format!(" for lifetime parameter {}in generic type", br_string(br)) } - infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!( + RegionVariableOrigin::BoundRegion( + _, + br, + BoundRegionConversionTime::AssocTypeProjection(def_id), + ) => format!( " for lifetime parameter {}in trait containing associated type `{}`", br_string(br), self.tcx.associated_item(def_id).name() ), - infer::RegionParameterDefinition(_, name) => { + RegionVariableOrigin::RegionParameterDefinition(_, name) => { format!(" for lifetime parameter `{name}`") } - infer::UpvarRegion(ref upvar_id, _) => { + RegionVariableOrigin::UpvarRegion(ref upvar_id, _) => { let var_name = self.tcx.hir_name(upvar_id.var_path.hir_id); format!(" for capture of `{var_name}` by closure") } - infer::Nll(..) => bug!("NLL variable found in lexical phase"), + RegionVariableOrigin::Nll(..) => bug!("NLL variable found in lexical phase"), }; struct_span_code_err!( @@ -1090,7 +1109,7 @@ fn msg_span_from_named_region<'tcx>( ty::ReEarlyParam(br) => { let param_def_id = tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id; let span = tcx.def_span(param_def_id); - let text = if br.has_name() { + let text = if br.is_named() { format!("the lifetime `{}` as defined here", br.name) } else { "the anonymous lifetime as defined here".to_string() @@ -1098,13 +1117,14 @@ fn msg_span_from_named_region<'tcx>( (text, Some(span)) } ty::ReLateParam(ref fr) => { - if !fr.kind.is_named() + if !fr.kind.is_named(tcx) && let Some((ty, _)) = find_anon_type(tcx, generic_param_scope, region) { ("the anonymous lifetime defined here".to_string(), Some(ty.span)) } else { match fr.kind { - ty::LateParamRegionKind::Named(param_def_id, name) => { + ty::LateParamRegionKind::Named(param_def_id) => { + let name = tcx.item_name(param_def_id); let span = tcx.def_span(param_def_id); let text = if name == kw::UnderscoreLifetime { "the anonymous lifetime as defined here".to_string() @@ -1126,9 +1146,12 @@ fn msg_span_from_named_region<'tcx>( } ty::ReStatic => ("the static lifetime".to_owned(), alt_span), ty::RePlaceholder(ty::PlaceholderRegion { - bound: ty::BoundRegion { kind: ty::BoundRegionKind::Named(def_id, name), .. }, + bound: ty::BoundRegion { kind: ty::BoundRegionKind::Named(def_id), .. }, .. - }) => (format!("the lifetime `{name}` as defined here"), Some(tcx.def_span(def_id))), + }) => ( + format!("the lifetime `{}` as defined here", tcx.item_name(def_id)), + Some(tcx.def_span(def_id)), + ), ty::RePlaceholder(ty::PlaceholderRegion { bound: ty::BoundRegion { kind: ty::BoundRegionKind::Anon, .. }, .. 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 3804c13acce..c0daf08ce07 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -8,9 +8,7 @@ use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::{MatchSource, Node}; -use rustc_middle::traits::{ - IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, -}; +use rustc_middle::traits::{MatchExpressionArmCause, ObligationCause, ObligationCauseCode}; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt}; @@ -196,8 +194,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (Some(exp), Some(found)) if self.same_type_modulo_infer(exp, found) => match cause .code() { - ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => { - let then_span = self.find_block_span_from_hir_id(*then_id); + ObligationCauseCode::IfExpression { expr_id, .. } => { + let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::If(_, then_expr, _), .. + }) = self.tcx.hir_node(*expr_id) + else { + return; + }; + let then_span = self.find_block_span_from_hir_id(then_expr.hir_id); Some(ConsiderAddingAwait::BothFuturesSugg { first: then_span.shrink_to_hi(), second: exp_span.shrink_to_hi(), @@ -232,8 +236,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span: then_span.shrink_to_hi(), }) } - ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => { - let then_span = self.find_block_span_from_hir_id(*then_id); + ObligationCauseCode::IfExpression { expr_id, .. } => { + let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::If(_, then_expr, _), .. + }) = self.tcx.hir_node(*expr_id) + else { + return; + }; + let then_span = self.find_block_span_from_hir_id(then_expr.hir_id); Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() }) } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 39f115ce0cd..98f67257fd1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -4,7 +4,7 @@ use rustc_errors::{Applicability, Diag, E0283, E0284, E0790, MultiSpan, struct_s use rustc_hir as hir; use rustc_hir::LangItem; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_hir::intravisit::Visitor as _; use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt}; use rustc_infer::traits::util::elaborate; @@ -12,6 +12,7 @@ use rustc_infer::traits::{ Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation, }; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _}; +use rustc_session::parse::feature_err_unstable_feature_bound; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use tracing::{debug, instrument}; @@ -128,19 +129,26 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>( }, ); - let predicates = - tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx); - for (pred, span) in elaborate(tcx, predicates.into_iter()) { - let kind = pred.kind(); - if let ty::ClauseKind::Trait(trait_pred) = kind.skip_binder() - && param_env_candidate_may_apply(kind.rebind(trait_pred)) - { - if kind.rebind(trait_pred.trait_ref) - == ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id())) + // If our `body_id` has been set (and isn't just from a dummy obligation cause), + // then try to look for a param-env clause that would apply. The way we compute + // this is somewhat manual, since we need the spans, so we elaborate this directly + // from `predicates_of` rather than actually looking at the param-env which + // otherwise would be more appropriate. + let body_id = obligation.cause.body_id; + if body_id != CRATE_DEF_ID { + let predicates = tcx.predicates_of(body_id.to_def_id()).instantiate_identity(tcx); + for (pred, span) in elaborate(tcx, predicates.into_iter()) { + let kind = pred.kind(); + if let ty::ClauseKind::Trait(trait_pred) = kind.skip_binder() + && param_env_candidate_may_apply(kind.rebind(trait_pred)) { - ambiguities.push(CandidateSource::ParamEnv(tcx.def_span(trait_pred.def_id()))) - } else { - ambiguities.push(CandidateSource::ParamEnv(span)) + if kind.rebind(trait_pred.trait_ref) + == ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id())) + { + ambiguities.push(CandidateSource::ParamEnv(tcx.def_span(trait_pred.def_id()))) + } else { + ambiguities.push(CandidateSource::ParamEnv(span)) + } } } } @@ -355,7 +363,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && self.tcx.trait_of_item(*item_id) == Some(*trait_id) && let None = self.tainted_by_errors() { - let (verb, noun) = match self.tcx.associated_item(item_id).kind { + let assoc_item = self.tcx.associated_item(item_id); + let (verb, noun) = match assoc_item.kind { ty::AssocKind::Const { .. } => ("refer to the", "constant"), ty::AssocKind::Fn { .. } => ("call", "function"), // This is already covered by E0223, but this following single match @@ -374,17 +383,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); err.code(E0790); - if let Some(local_def_id) = data.trait_ref.def_id.as_local() - && let hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, trait_ident, _, _, trait_item_refs), - .. - }) = self.tcx.hir_node_by_def_id(local_def_id) - && let Some(method_ref) = trait_item_refs - .iter() - .find(|item_ref| item_ref.ident == *assoc_item_ident) - { + if item_id.is_local() { + let trait_ident = self.tcx.item_name(*trait_id); err.span_label( - method_ref.span, + self.tcx.def_span(*item_id), format!("`{trait_ident}::{assoc_item_ident}` defined here"), ); } @@ -610,6 +612,30 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) .with_span_label(span, format!("cannot normalize `{alias}`")) } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(sym)) => { + if let Some(e) = self.tainted_by_errors() { + return e; + } + + let mut err; + + if self.tcx.features().staged_api() { + err = self.dcx().struct_span_err( + span, + format!("unstable feature `{sym}` is used without being enabled."), + ); + + err.help(format!("The feature can be enabled by marking the current item with `#[unstable_feature_bound({sym})]`")); + } else { + err = feature_err_unstable_feature_bound( + &self.tcx.sess, + sym, + span, + format!("use of unstable library feature `{sym}`"), + ); + } + err + } _ => { if let Some(e) = self.tainted_by_errors() { 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 0c88bd3dcbc..1ac309da101 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 @@ -47,8 +47,8 @@ use crate::infer::{self, InferCtxt, InferCtxtExt as _}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::{ MismatchedProjectionTypes, NormalizeExt, Obligation, ObligationCause, ObligationCauseCode, - ObligationCtxt, Overflow, PredicateObligation, SelectionContext, SelectionError, - SignatureMismatch, TraitDynIncompatible, elaborate, specialization_graph, + ObligationCtxt, PredicateObligation, SelectionContext, SelectionError, elaborate, + specialization_graph, }; impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { @@ -647,6 +647,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ty::PredicateKind::ConstEquate { .. } // Ambiguous predicates should never error | ty::PredicateKind::Ambiguous + // We never return Err when proving UnstableFeature goal. + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature{ .. }) | ty::PredicateKind::NormalizesTo { .. } | ty::PredicateKind::AliasRelate { .. } | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType { .. }) => { @@ -659,7 +661,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - SignatureMismatch(box SignatureMismatchData { + SelectionError::SignatureMismatch(box SignatureMismatchData { found_trait_ref, expected_trait_ref, terr: terr @ TypeError::CyclicTy(_), @@ -669,7 +671,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { expected_trait_ref, terr, ), - SignatureMismatch(box SignatureMismatchData { + SelectionError::SignatureMismatch(box SignatureMismatchData { found_trait_ref, expected_trait_ref, terr: _, @@ -690,7 +692,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { def_id, ), - TraitDynIncompatible(did) => { + SelectionError::TraitDynIncompatible(did) => { let violations = self.tcx.dyn_compatibility_violations(did); report_dyn_incompatibility(self.tcx, span, None, did, violations) } @@ -710,12 +712,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Already reported in the query. SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(guar)) | // Already reported. - Overflow(OverflowError::Error(guar)) => { + SelectionError::Overflow(OverflowError::Error(guar)) => { self.set_tainted_by_errors(guar); return guar }, - Overflow(_) => { + SelectionError::Overflow(_) => { bug!("overflow should be handled before the `report_selection_error` path"); } @@ -775,7 +777,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, span: Span, ) -> Diag<'a> { - // FIXME(const_trait_impl): We should recompute the predicate with `~const` + // FIXME(const_trait_impl): We should recompute the predicate with `[const]` // if it's `const`, and if it holds, explain that this bound only // *conditionally* holds. If that fails, we should also do selection // to drill this down to an impl or built-in source, so we can @@ -1186,7 +1188,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty: Ty<'tcx>, obligation: &PredicateObligation<'tcx>, ) -> Diag<'a> { - let span = obligation.cause.span; + let param = obligation.cause.body_id; + let hir::GenericParamKind::Const { ty: &hir::Ty { span, .. }, .. } = + self.tcx.hir_node_by_def_id(param).expect_generic_param().kind + else { + bug!() + }; let mut diag = match ty.kind() { ty::Float(_) => { @@ -1850,7 +1857,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let trait_def_id = trait_pred.def_id(); let trait_name = self.tcx.item_name(trait_def_id); let crate_name = self.tcx.crate_name(trait_def_id.krate); - if let Some(other_trait_def_id) = self.tcx.all_traits().find(|def_id| { + if let Some(other_trait_def_id) = self.tcx.all_traits_including_private().find(|def_id| { trait_name == self.tcx.item_name(trait_def_id) && trait_def_id.krate != def_id.krate && crate_name == self.tcx.crate_name(def_id.krate) @@ -1928,7 +1935,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { StringPart::highlighted("multiple different versions".to_string()), StringPart::normal(" of crate `".to_string()), StringPart::highlighted(format!("{crate_name}")), - StringPart::normal("` in the dependency graph\n".to_string()), + StringPart::normal("` in the dependency graph".to_string()), ], ); if points_at_type { 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 89dab90dc68..2344bc79f21 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 @@ -11,7 +11,9 @@ use rustc_macros::LintDiagnostic; use rustc_middle::bug; use rustc_middle::ty::print::PrintTraitRefExt; use rustc_middle::ty::{self, GenericArgsRef, GenericParamDef, GenericParamDefKind, TyCtxt}; -use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; +use rustc_session::lint::builtin::{ + MALFORMED_DIAGNOSTIC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, +}; use rustc_span::{Span, Symbol, sym}; use tracing::{debug, info}; @@ -334,7 +336,7 @@ pub struct OnUnimplementedNote { pub append_const_msg: Option<AppendConstMessage>, } -/// Append a message for `~const Trait` errors. +/// Append a message for `[const] Trait` errors. #[derive(Clone, Copy, PartialEq, Eq, Debug, Default)] pub enum AppendConstMessage { #[default] @@ -382,7 +384,7 @@ impl IgnoredDiagnosticOption { 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, + 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 }, @@ -533,7 +535,7 @@ impl<'tcx> OnUnimplementedDirective { if is_diagnostic_namespace_variant { if let Some(def_id) = item_def_id.as_local() { tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(def_id), vec![item.span()], MalformedOnUnimplementedAttrLint::new(item.span()), @@ -689,7 +691,7 @@ impl<'tcx> OnUnimplementedDirective { if let Some(item_def_id) = item_def_id.as_local() { tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id), report_span, MalformedOnUnimplementedAttrLint::new(report_span), @@ -702,7 +704,7 @@ impl<'tcx> OnUnimplementedDirective { Attribute::Unparsed(p) if !matches!(p.args, AttrArgs::Empty) => { if let Some(item_def_id) = item_def_id.as_local() { tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id), attr.span(), MalformedOnUnimplementedAttrLint::new(attr.span()), @@ -712,7 +714,7 @@ impl<'tcx> OnUnimplementedDirective { _ => { if let Some(item_def_id) = item_def_id.as_local() { tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id), attr.span(), MissingOptionsForOnUnimplementedAttr, @@ -859,7 +861,7 @@ impl<'tcx> OnUnimplementedFormatString { if self.is_diagnostic_namespace_variant { if let Some(trait_def_id) = trait_def_id.as_local() { tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, tcx.local_def_id_to_hir_id(trait_def_id), self.span, WrappedParserError { description: e.description, label: e.label }, 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 3e8b906fa93..1954f8a1f63 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 @@ -7,7 +7,7 @@ use rustc_middle::ty::{GenericParamDefKind, TyCtxt}; use rustc_parse_format::{ Argument, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position, }; -use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; +use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_FORMAT_LITERALS; use rustc_span::def_id::DefId; use rustc_span::{InnerSpan, Span, Symbol, kw, sym}; @@ -69,7 +69,7 @@ impl FormatWarning { let this = tcx.item_ident(item_def_id); if let Some(item_def_id) = item_def_id.as_local() { tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, tcx.local_def_id_to_hir_id(item_def_id), span, UnknownFormatParameterForOnUnimplementedAttr { @@ -82,7 +82,7 @@ impl FormatWarning { FormatWarning::PositionalArgument { span, .. } => { if let Some(item_def_id) = item_def_id.as_local() { tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, tcx.local_def_id_to_hir_id(item_def_id), span, DisallowedPositionalArgument, @@ -92,7 +92,7 @@ impl FormatWarning { FormatWarning::InvalidSpecifier { span, .. } => { if let Some(item_def_id) = item_def_id.as_local() { tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, tcx.local_def_id_to_hir_id(item_def_id), span, InvalidFormatSpecifier, 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 6d07ae021ae..bd1d29826e6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1187,6 +1187,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { has_custom_message: bool, ) -> bool { let span = obligation.cause.span; + let param_env = obligation.param_env; + + let mk_result = |trait_pred_and_new_ty| { + let obligation = + self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty); + self.predicate_must_hold_modulo_regions(&obligation) + }; let code = match obligation.cause.code() { ObligationCauseCode::FunctionArg { parent_code, .. } => parent_code, @@ -1195,6 +1202,76 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { c @ ObligationCauseCode::WhereClauseInExpr(_, _, hir_id, _) if self.tcx.hir_span(*hir_id).lo() == span.lo() => { + // `hir_id` corresponds to the HIR node that introduced a `where`-clause obligation. + // If that obligation comes from a type in an associated method call, we need + // special handling here. + if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(*hir_id) + && let hir::ExprKind::Call(base, _) = expr.kind + && let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, segment)) = base.kind + && let hir::Node::Expr(outer) = self.tcx.parent_hir_node(expr.hir_id) + && let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mtbl, _) = outer.kind + && ty.span == span + { + // We've encountered something like `&str::from("")`, where the intended code + // was likely `<&str>::from("")`. The former is interpreted as "call method + // `from` on `str` and borrow the result", while the latter means "call method + // `from` on `&str`". + + let trait_pred_and_imm_ref = poly_trait_pred.map_bound(|p| { + (p, Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, p.self_ty())) + }); + let trait_pred_and_mut_ref = poly_trait_pred.map_bound(|p| { + (p, Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, p.self_ty())) + }); + + let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref); + let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref); + let sugg_msg = |pre: &str| { + format!( + "you likely meant to call the associated function `{FN}` for type \ + `&{pre}{TY}`, but the code as written calls associated function `{FN}` on \ + type `{TY}`", + FN = segment.ident, + TY = poly_trait_pred.self_ty(), + ) + }; + match (imm_ref_self_ty_satisfies_pred, mut_ref_self_ty_satisfies_pred, mtbl) { + (true, _, hir::Mutability::Not) | (_, true, hir::Mutability::Mut) => { + err.multipart_suggestion_verbose( + sugg_msg(mtbl.prefix_str()), + vec![ + (outer.span.shrink_to_lo(), "<".to_string()), + (span.shrink_to_hi(), ">".to_string()), + ], + Applicability::MachineApplicable, + ); + } + (true, _, hir::Mutability::Mut) => { + // There's an associated function found on the immutable borrow of the + err.multipart_suggestion_verbose( + sugg_msg("mut "), + vec![ + (outer.span.shrink_to_lo().until(span), "<&".to_string()), + (span.shrink_to_hi(), ">".to_string()), + ], + Applicability::MachineApplicable, + ); + } + (_, true, hir::Mutability::Not) => { + err.multipart_suggestion_verbose( + sugg_msg(""), + vec![ + (outer.span.shrink_to_lo().until(span), "<&mut ".to_string()), + (span.shrink_to_hi(), ">".to_string()), + ], + Applicability::MachineApplicable, + ); + } + _ => {} + } + // If we didn't return early here, we would instead suggest `&&str::from("")`. + return false; + } c } c if matches!( @@ -1220,8 +1297,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { never_suggest_borrow.push(def_id); } - let param_env = obligation.param_env; - // Try to apply the original trait bound by borrowing. let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>, blacklist: &[DefId]| @@ -1243,15 +1318,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) }); - let mk_result = |trait_pred_and_new_ty| { - let obligation = - self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty); - self.predicate_must_hold_modulo_regions(&obligation) - }; let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref); let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref); - let (ref_inner_ty_satisfies_pred, ref_inner_ty_mut) = + let (ref_inner_ty_satisfies_pred, ref_inner_ty_is_mut) = if let ObligationCauseCode::WhereClauseInExpr(..) = obligation.cause.code() && let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind() { @@ -1263,117 +1333,139 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (false, false) }; - if imm_ref_self_ty_satisfies_pred - || mut_ref_self_ty_satisfies_pred - || ref_inner_ty_satisfies_pred - { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - // We don't want a borrowing suggestion on the fields in structs, - // ``` - // struct Foo { - // the_foos: Vec<Foo> - // } - // ``` - if !matches!( - span.ctxt().outer_expn_data().kind, - ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) - ) { - return false; - } - if snippet.starts_with('&') { - // This is already a literal borrow and the obligation is failing - // somewhere else in the obligation chain. Do not suggest non-sense. - return false; - } - // We have a very specific type of error, where just borrowing this argument - // might solve the problem. In cases like this, the important part is the - // original type obligation, not the last one that failed, which is arbitrary. - // Because of this, we modify the error to refer to the original obligation and - // return early in the caller. - - let msg = format!( - "the trait bound `{}` is not satisfied", - self.tcx.short_string(old_pred, err.long_ty_path()), - ); - let self_ty_str = - self.tcx.short_string(old_pred.self_ty().skip_binder(), err.long_ty_path()); - if has_custom_message { - err.note(msg); - } else { - err.messages = vec![(rustc_errors::DiagMessage::from(msg), Style::NoStyle)]; - } - err.span_label( - span, - format!( - "the trait `{}` is not implemented for `{self_ty_str}`", - old_pred.print_modifiers_and_trait_path() - ), - ); + let is_immut = imm_ref_self_ty_satisfies_pred + || (ref_inner_ty_satisfies_pred && !ref_inner_ty_is_mut); + let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_is_mut; + if !is_immut && !is_mut { + return false; + } + let Ok(_snippet) = self.tcx.sess.source_map().span_to_snippet(span) else { + return false; + }; + // We don't want a borrowing suggestion on the fields in structs + // ``` + // #[derive(Clone)] + // struct Foo { + // the_foos: Vec<Foo> + // } + // ``` + if !matches!( + span.ctxt().outer_expn_data().kind, + ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) + ) { + return false; + } + // We have a very specific type of error, where just borrowing this argument + // might solve the problem. In cases like this, the important part is the + // original type obligation, not the last one that failed, which is arbitrary. + // Because of this, we modify the error to refer to the original obligation and + // return early in the caller. - if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred { - err.span_suggestions( - span.shrink_to_lo(), - "consider borrowing here", - ["&".to_string(), "&mut ".to_string()], - Applicability::MaybeIncorrect, - ); - } else { - let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut; - let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" }); - let sugg_msg = format!( - "consider{} borrowing here", - if is_mut { " mutably" } else { "" } - ); + let mut label = || { + let msg = format!( + "the trait bound `{}` is not satisfied", + self.tcx.short_string(old_pred, err.long_ty_path()), + ); + let self_ty_str = + self.tcx.short_string(old_pred.self_ty().skip_binder(), err.long_ty_path()); + if has_custom_message { + err.note(msg); + } else { + err.messages = vec![(rustc_errors::DiagMessage::from(msg), Style::NoStyle)]; + } + err.span_label( + span, + format!( + "the trait `{}` is not implemented for `{self_ty_str}`", + old_pred.print_modifiers_and_trait_path() + ), + ); + }; - // Issue #109436, we need to add parentheses properly for method calls - // for example, `foo.into()` should be `(&foo).into()` - if let Some(_) = - self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50)) - { - err.multipart_suggestion_verbose( - sugg_msg, - vec![ - (span.shrink_to_lo(), format!("({sugg_prefix}")), - (span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MaybeIncorrect, - ); - return true; - } + let mut sugg_prefixes = vec![]; + if is_immut { + sugg_prefixes.push("&"); + } + if is_mut { + sugg_prefixes.push("&mut "); + } + let sugg_msg = format!( + "consider{} borrowing here", + if is_mut && !is_immut { " mutably" } else { "" }, + ); - // Issue #104961, we need to add parentheses properly for compound expressions - // for example, `x.starts_with("hi".to_string() + "you")` - // should be `x.starts_with(&("hi".to_string() + "you"))` - let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) - else { - return false; - }; - let mut expr_finder = FindExprBySpan::new(span, self.tcx); - expr_finder.visit_expr(body.value); - let Some(expr) = expr_finder.result else { - return false; - }; - let needs_parens = expr_needs_parens(expr); + // Issue #104961, we need to add parentheses properly for compound expressions + // for example, `x.starts_with("hi".to_string() + "you")` + // should be `x.starts_with(&("hi".to_string() + "you"))` + let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else { + return false; + }; + let mut expr_finder = FindExprBySpan::new(span, self.tcx); + expr_finder.visit_expr(body.value); - let span = if needs_parens { span } else { span.shrink_to_lo() }; - let suggestions = if !needs_parens { - vec![(span.shrink_to_lo(), sugg_prefix)] - } else { + if let Some(ty) = expr_finder.ty_result { + if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(ty.hir_id) + && let hir::ExprKind::Path(hir::QPath::TypeRelative(_, _)) = expr.kind + && ty.span == span + { + // We've encountered something like `str::from("")`, where the intended code + // was likely `<&str>::from("")`. #143393. + label(); + err.multipart_suggestions( + sugg_msg, + sugg_prefixes.into_iter().map(|sugg_prefix| { vec![ - (span.shrink_to_lo(), format!("{sugg_prefix}(")), - (span.shrink_to_hi(), ")".to_string()), + (span.shrink_to_lo(), format!("<{sugg_prefix}")), + (span.shrink_to_hi(), ">".to_string()), ] - }; - err.multipart_suggestion_verbose( - sugg_msg, - suggestions, - Applicability::MaybeIncorrect, - ); - } + }), + Applicability::MaybeIncorrect, + ); return true; } + return false; } - return false; + let Some(expr) = expr_finder.result else { + return false; + }; + if let hir::ExprKind::AddrOf(_, _, _) = expr.kind { + return false; + } + let needs_parens_post = expr_needs_parens(expr); + let needs_parens_pre = match self.tcx.parent_hir_node(expr.hir_id) { + Node::Expr(e) + if let hir::ExprKind::MethodCall(_, base, _, _) = e.kind + && base.hir_id == expr.hir_id => + { + true + } + _ => false, + }; + + label(); + let suggestions = sugg_prefixes.into_iter().map(|sugg_prefix| { + match (needs_parens_pre, needs_parens_post) { + (false, false) => vec![(span.shrink_to_lo(), sugg_prefix.to_string())], + // We have something like `foo.bar()`, where we want to bororw foo, so we need + // to suggest `(&mut foo).bar()`. + (false, true) => vec![ + (span.shrink_to_lo(), format!("{sugg_prefix}(")), + (span.shrink_to_hi(), ")".to_string()), + ], + // Issue #109436, we need to add parentheses properly for method calls + // for example, `foo.into()` should be `(&foo).into()` + (true, false) => vec![ + (span.shrink_to_lo(), format!("({sugg_prefix}")), + (span.shrink_to_hi(), ")".to_string()), + ], + (true, true) => vec![ + (span.shrink_to_lo(), format!("({sugg_prefix}(")), + (span.shrink_to_hi(), "))".to_string()), + ], + } + }); + err.multipart_suggestions(sugg_msg, suggestions, Applicability::MaybeIncorrect); + return true; }; if let ObligationCauseCode::ImplDerived(cause) = &*code { @@ -1511,12 +1603,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { 'outer: loop { while let hir::ExprKind::AddrOf(_, _, borrowed) = expr.kind { count += 1; - let span = if expr.span.eq_ctxt(borrowed.span) { - expr.span.until(borrowed.span) - } else { - expr.span.with_hi(expr.span.lo() + BytePos(1)) - }; + let span = + if let Some(borrowed_span) = borrowed.span.find_ancestor_inside(expr.span) { + expr.span.until(borrowed_span) + } else { + break 'outer; + }; + // Double check that the span we extracted actually corresponds to a borrow, + // rather than some macro garbage. match self.tcx.sess.source_map().span_to_snippet(span) { Ok(snippet) if snippet.starts_with("&") => {} _ => break 'outer, @@ -2721,6 +2816,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ObligationCauseCode::TupleElem => { err.note("only the last element of a tuple may have a dynamically sized type"); } + ObligationCauseCode::DynCompatible(span) => { + err.multipart_suggestion( + "you might have meant to use `Self` to refer to the implementing type", + vec![(span, "Self".into())], + Applicability::MachineApplicable, + ); + } ObligationCauseCode::WhereClause(item_def_id, span) | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..) | ObligationCauseCode::HostEffectInExpr(item_def_id, span, ..) @@ -2872,13 +2974,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => (), } } - let descr = format!("required by {a} bound in `{item_name}`"); - if span.is_visible(sm) { - let msg = format!("required by {this} in `{short_item_name}`"); - multispan.push_span_label(span, msg); - err.span_note(multispan, descr); + + // If this is from a format string literal desugaring, + // we've already said "required by this formatting parameter" + let is_in_fmt_lit = if let Some(s) = err.span.primary_span() { + matches!(s.desugaring_kind(), Some(DesugaringKind::FormatLiteral { .. })) } else { - err.span_note(tcx.def_span(item_def_id), descr); + false + }; + if !is_in_fmt_lit { + let descr = format!("required by {a} bound in `{item_name}`"); + if span.is_visible(sm) { + let msg = format!("required by {this} in `{short_item_name}`"); + multispan.push_span_label(span, msg); + err.span_note(multispan, descr); + } else { + err.span_note(tcx.def_span(item_def_id), descr); + } } if let Some(note) = note { err.note(note); @@ -3607,6 +3719,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); suggest_remove_deref(err, &expr); } + ObligationCauseCode::UnsizedNonPlaceExpr(span) => { + err.span_note( + span, + "unsized values must be place expressions and cannot be put in temporaries", + ); + } } } @@ -3973,7 +4091,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) = expr.kind { if Some(*span) != err.span.primary_span() { - err.span_label(*span, "required by a bound introduced by this call"); + let msg = if span.is_desugaring(DesugaringKind::FormatLiteral { source: true }) + { + "required by this formatting parameter" + } else if span.is_desugaring(DesugaringKind::FormatLiteral { source: false }) { + "required by a formatting parameter in this expression" + } else { + "required by a bound introduced by this call" + }; + err.span_label(*span, msg); } } @@ -4407,7 +4533,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { candidate_impls: &[ImplCandidate<'tcx>], span: Span, ) { - // We can only suggest the slice coersion for function and binary operation arguments, + // We can only suggest the slice coercion for function and binary operation arguments, // since the suggestion would make no sense in turbofish or call let (ObligationCauseCode::BinOp { .. } | ObligationCauseCode::FunctionArg { .. }) = obligation.cause.code() diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 7bf49056e29..90cdf75265d 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -643,7 +643,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { // Do not suggest constraining the `&self` param, but rather the return type. // If that is wrong (because it is not sufficient), a follow up error will tell the // user to fix it. This way we lower the chances of *over* constraining, but still - // get the cake of "correctly" contrained in two steps. + // get the cake of "correctly" constrained in two steps. visitor.visit_ty_unambig(self.ty_sup); } visitor.visit_ty_unambig(self.ty_sub); diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs index 84e7686fdd3..3471036256d 100644 --- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs @@ -32,21 +32,22 @@ impl<'a> DescriptionCtx<'a> { } else { tcx.def_span(scope) }; - if br.has_name() { + if br.is_named() { (Some(span), "as_defined", br.name.to_string()) } else { (Some(span), "as_defined_anon", String::new()) } } ty::ReLateParam(ref fr) => { - if !fr.kind.is_named() + if !fr.kind.is_named(tcx) && let Some((ty, _)) = find_anon_type(tcx, generic_param_scope, region) { (Some(ty.span), "defined_here", String::new()) } else { let scope = fr.scope.expect_local(); match fr.kind { - ty::LateParamRegionKind::Named(_, name) => { + ty::LateParamRegionKind::Named(def_id) => { + let name = tcx.item_name(def_id); let span = if let Some(param) = tcx .hir_get_generics(scope) .and_then(|generics| generics.get_named(name)) @@ -163,12 +164,14 @@ impl RegionExplanation<'_> { impl Subdiagnostic for RegionExplanation<'_> { fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { + diag.store_args(); diag.arg("pref_kind", self.prefix); diag.arg("suff_kind", self.suffix); diag.arg("desc_kind", self.desc.kind); diag.arg("desc_arg", self.desc.arg); let msg = diag.eagerly_translate(fluent::trait_selection_region_explanation); + diag.restore_args(); if let Some(span) = self.desc.span { diag.span_note(span, msg); } else { diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index b247c2c2968..1a24254d57f 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -143,6 +143,16 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< None } } + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { + let arg = self.shallow_resolve_term(arg); + if arg.is_trivially_wf(self.tcx) { + Some(Certainty::Yes) + } else if arg.is_infer() { + Some(Certainty::AMBIGUOUS) + } else { + None + } + } _ => None, } } @@ -154,7 +164,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< ) -> ty::GenericArg<'tcx> { match arg.kind() { ty::GenericArgKind::Lifetime(_) => { - self.next_region_var(RegionVariableOrigin::MiscVariable(span)).into() + self.next_region_var(RegionVariableOrigin::Misc(span)).into() } ty::GenericArgKind::Type(_) => self.next_ty_var(span).into(), ty::GenericArgKind::Const(_) => self.next_const_var(span).into(), @@ -203,13 +213,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< // 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, - ) + make_query_region_constraints(self.tcx, region_obligations, region_constraints) }); let mut seen = FxHashSet::default(); diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index ed99c678a4d..d56042a5ca2 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{ }; use rustc_next_trait_solver::delegate::SolverDelegate as _; use rustc_next_trait_solver::solve::{ - GenerateProofTree, GoalEvaluation, GoalStalledOn, HasChanged, SolverDelegateEvalExt as _, + GoalEvaluation, GoalStalledOn, HasChanged, SolverDelegateEvalExt as _, }; use rustc_span::Span; use thin_vec::ThinVec; @@ -106,14 +106,11 @@ impl<'tcx> ObligationStorage<'tcx> { 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; + let result = <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal( + goal, + o.cause.span, + stalled_on.take(), + ); matches!(result, Ok(GoalEvaluation { has_changed: HasChanged::Yes, .. })) }) .map(|(o, _)| o), @@ -207,14 +204,7 @@ where continue; } - let result = delegate - .evaluate_root_goal( - goal, - GenerateProofTree::No, - obligation.cause.span, - stalled_on, - ) - .0; + let result = delegate.evaluate_root_goal(goal, obligation.cause.span, stalled_on); self.inspect_evaluated_obligation(infcx, &obligation, &result); let GoalEvaluation { certainty, has_changed, stalled_on } = match result { Ok(result) => result, 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 36a8ae675c0..e31d1052d16 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -11,9 +11,7 @@ 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, GoalEvaluation, SolverDelegateEvalExt as _, -}; +use rustc_next_trait_solver::solve::{GoalEvaluation, SolverDelegateEvalExt as _}; use tracing::{instrument, trace}; use crate::solve::delegate::SolverDelegate; @@ -39,7 +37,9 @@ pub(super) fn fulfillment_error_for_no_solution<'tcx>( ty::ConstKind::Unevaluated(uv) => { infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args) } - ty::ConstKind::Param(param_ct) => param_ct.find_ty_from_env(obligation.param_env), + ty::ConstKind::Param(param_ct) => { + param_ct.find_const_ty_from_env(obligation.param_env) + } ty::ConstKind::Value(cv) => cv.ty, kind => span_bug!( obligation.cause.span, @@ -90,15 +90,11 @@ pub(super) fn fulfillment_error_for_stalled<'tcx>( root_obligation: PredicateObligation<'tcx>, ) -> FulfillmentError<'tcx> { let (code, refine_obligation) = infcx.probe(|_| { - match <&SolverDelegate<'tcx>>::from(infcx) - .evaluate_root_goal( - root_obligation.as_goal(), - GenerateProofTree::No, - root_obligation.cause.span, - None, - ) - .0 - { + match <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal( + root_obligation.as_goal(), + root_obligation.cause.span, + None, + ) { Ok(GoalEvaluation { certainty: Certainty::Maybe(MaybeCause::Ambiguity), .. }) => { (FulfillmentErrorCode::Ambiguity { overflow: None }, true) } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index b0c8fa1f217..308486811e6 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -20,7 +20,7 @@ use rustc_middle::ty::{TyCtxt, VisitorResult, try_visit}; use rustc_middle::{bug, ty}; 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_next_trait_solver::solve::{MaybeCause, SolverDelegateEvalExt as _}; use rustc_span::Span; use tracing::instrument; @@ -37,7 +37,7 @@ pub struct InspectGoal<'a, 'tcx> { orig_values: Vec<ty::GenericArg<'tcx>>, goal: Goal<'tcx, ty::Predicate<'tcx>>, result: Result<Certainty, NoSolution>, - evaluation_kind: inspect::CanonicalGoalEvaluationKind<TyCtxt<'tcx>>, + evaluation_kind: inspect::GoalEvaluationKind<TyCtxt<'tcx>>, normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>, source: GoalSource, } @@ -248,9 +248,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { // considering the constrained RHS, and pass the resulting certainty to // `InspectGoal::new` so that the goal has the right result (and maintains // the impression that we don't do this normalizes-to infer hack at all). - let (nested, proof_tree) = - infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes, None); - let proof_tree = proof_tree.unwrap(); + let (nested, proof_tree) = infcx.evaluate_root_goal_for_proof_tree(goal, span); let nested_goals_result = nested.and_then(|(nested, _)| { normalizes_to_term_hack.constrain_and( infcx, @@ -284,9 +282,8 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { // into another candidate who ends up with different inference // 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, None).1) - .unwrap(); + let proof_tree = + infcx.probe(|_| infcx.evaluate_root_goal_for_proof_tree(goal, span).1); InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source) } } @@ -396,8 +393,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { let mut candidates = vec![]; let last_eval_step = match &self.evaluation_kind { // An annoying edge case in case the recursion limit is 0. - inspect::CanonicalGoalEvaluationKind::Overflow => return vec![], - inspect::CanonicalGoalEvaluationKind::Evaluation { final_revision } => final_revision, + inspect::GoalEvaluationKind::Overflow => return vec![], + inspect::GoalEvaluationKind::Evaluation { final_revision } => final_revision, }; let mut nested_goals = vec![]; @@ -429,10 +426,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { ) -> Self { let infcx = <&SolverDelegate<'tcx>>::from(infcx); - let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, evaluation } = root; + let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, kind, result } = root; // If there's a normalizes-to goal, AND the evaluation result with the result of // constraining the normalizes-to RHS and computing the nested goals. - let result = evaluation.result.and_then(|ok| { + let result = result.and_then(|ok| { let nested_goals_certainty = term_hack_and_nested_certainty.map_or(Ok(Certainty::Yes), |(_, c)| c)?; Ok(ok.value.certainty.and(nested_goals_certainty)) @@ -444,7 +441,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { orig_values, goal: eager_resolve_vars(infcx, uncanonicalized_goal), result, - evaluation_kind: evaluation.kind, + evaluation_kind: kind, normalizes_to_term_hack: term_hack_and_nested_certainty.map(|(n, _)| n), source, } @@ -488,13 +485,8 @@ impl<'tcx> InferCtxt<'tcx> { depth: usize, visitor: &mut V, ) -> V::Result { - let (_, proof_tree) = <&SolverDelegate<'tcx>>::from(self).evaluate_root_goal( - goal, - GenerateProofTree::Yes, - visitor.span(), - None, - ); - let proof_tree = proof_tree.unwrap(); + let (_, proof_tree) = <&SolverDelegate<'tcx>>::from(self) + .evaluate_root_goal_for_proof_tree(goal, visitor.span()); visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, None, GoalSource::Misc)) } } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 3ae908ec16b..759db1d18c0 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -800,6 +800,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { // FIXME(generic_const_exprs): you can absolutely add this as a where clauses | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {} ty::PredicateKind::Ambiguous => return false, }; diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 81893cdcc7e..ce5a4edeaaa 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -356,29 +356,38 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>( return IntersectionHasImpossibleObligations::Yes; } - let ocx = ObligationCtxt::new_with_diagnostics(infcx); + let ocx = ObligationCtxt::new(infcx); ocx.register_obligations(obligations.iter().cloned()); + let hard_errors = ocx.select_where_possible(); + if !hard_errors.is_empty() { + assert!( + hard_errors.iter().all(|e| e.is_true_error()), + "should not have detected ambiguity during first pass" + ); + return IntersectionHasImpossibleObligations::Yes; + } + + // Make a new `ObligationCtxt` and re-prove the ambiguities with a richer + // `FulfillmentError`. This is so that we can detect overflowing obligations + // without needing to run the `BestObligation` visitor on true errors. + let ambiguities = ocx.into_pending_obligations(); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); + ocx.register_obligations(ambiguities); let errors_and_ambiguities = ocx.select_all_or_error(); // We only care about the obligations that are *definitely* true errors. // Ambiguities do not prove the disjointness of two impls. let (errors, ambiguities): (Vec<_>, Vec<_>) = errors_and_ambiguities.into_iter().partition(|error| error.is_true_error()); - - if errors.is_empty() { - IntersectionHasImpossibleObligations::No { - overflowing_predicates: ambiguities - .into_iter() - .filter(|error| { - matches!( - error.code, - FulfillmentErrorCode::Ambiguity { overflow: Some(true) } - ) - }) - .map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate)) - .collect(), - } - } else { - IntersectionHasImpossibleObligations::Yes + assert!(errors.is_empty(), "should not have ambiguities during second pass"); + + IntersectionHasImpossibleObligations::No { + overflowing_predicates: ambiguities + .into_iter() + .filter(|error| { + matches!(error.code, FulfillmentErrorCode::Ambiguity { overflow: Some(true) }) + }) + .map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate)) + .collect(), } } else { for obligation in obligations { diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index ee30956295a..ea1eed95723 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -31,7 +31,7 @@ use crate::traits::{ /// /// Currently that is `Self` in supertraits. This is needed /// because `dyn_compatibility_violations` can't be used during -/// type collection. +/// type collection, as type collection is needed for `dyn_compatibility_violations` itself. #[instrument(level = "debug", skip(tcx), ret)] pub fn hir_ty_lowering_dyn_compatibility_violations( tcx: TyCtxt<'_>, @@ -238,6 +238,7 @@ fn predicate_references_self<'tcx>( // FIXME(generic_const_exprs): this can mention `Self` | ty::ClauseKind::ConstEvaluatable(..) | ty::ClauseKind::HostEffect(..) + | ty::ClauseKind::UnstableFeature(_) => None, } } @@ -278,6 +279,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => false, }) } @@ -593,7 +595,7 @@ fn receiver_is_dispatchable<'tcx>( // will cause ambiguity that the user can't really avoid. // // We leave out certain complexities of the param-env query here. Specifically, we: - // 1. Do not add `~const` bounds since there are no `dyn const Trait`s. + // 1. Do not add `[const]` bounds since there are no `dyn const Trait`s. // 2. Do not add RPITIT self projection bounds for defaulted methods, since we // are not constructing a param-env for "inside" of the body of the defaulted // method, so we don't really care about projecting to a specific RPIT type, diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index e77d9e32cb9..d694a092853 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -1,7 +1,8 @@ use rustc_hir::{self as hir, LangItem}; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes}; use rustc_infer::traits::{ - ImplDerivedHostCause, ImplSource, Obligation, ObligationCauseCode, PredicateObligation, + ImplDerivedHostCause, ImplSource, Obligation, ObligationCause, ObligationCauseCode, + PredicateObligation, }; use rustc_middle::span_bug; use rustc_middle::traits::query::NoSolution; @@ -44,6 +45,12 @@ pub fn evaluate_host_effect_obligation<'tcx>( Err(EvaluationFailure::NoSolution) => {} } + match evaluate_host_effect_from_conditionally_const_item_bounds(selcx, obligation) { + Ok(result) => return Ok(result), + Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), + Err(EvaluationFailure::NoSolution) => {} + } + match evaluate_host_effect_from_item_bounds(selcx, obligation) { Ok(result) => return Ok(result), Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), @@ -56,7 +63,7 @@ pub fn evaluate_host_effect_obligation<'tcx>( Err(EvaluationFailure::NoSolution) => {} } - match evaluate_host_effect_from_selection_candiate(selcx, obligation) { + match evaluate_host_effect_from_selection_candidate(selcx, obligation) { Ok(result) => return Ok(result), Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), Err(EvaluationFailure::NoSolution) => {} @@ -153,7 +160,9 @@ fn evaluate_host_effect_from_bounds<'tcx>( } } -fn evaluate_host_effect_from_item_bounds<'tcx>( +/// Assembles constness bounds from `~const` item bounds on alias types, which only +/// hold if the `~const` where bounds also hold and the parent trait is `~const`. +fn evaluate_host_effect_from_conditionally_const_item_bounds<'tcx>( selcx: &mut SelectionContext<'_, 'tcx>, obligation: &HostEffectObligation<'tcx>, ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { @@ -232,12 +241,72 @@ fn evaluate_host_effect_from_item_bounds<'tcx>( } } +/// Assembles constness bounds "normal" item bounds on aliases, which may include +/// unconditionally `const` bounds that are *not* conditional and thus always hold. +fn evaluate_host_effect_from_item_bounds<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { + let infcx = selcx.infcx; + let tcx = infcx.tcx; + let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx()); + let mut candidate = None; + + let mut consider_ty = obligation.predicate.self_ty(); + while let ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) = *consider_ty.kind() { + for clause in tcx.item_bounds(alias_ty.def_id).iter_instantiated(tcx, alias_ty.args) { + let bound_clause = clause.kind(); + let ty::ClauseKind::HostEffect(data) = bound_clause.skip_binder() else { + continue; + }; + let data = bound_clause.rebind(data); + if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id { + continue; + } + + if !drcx.args_may_unify( + obligation.predicate.trait_ref.args, + data.skip_binder().trait_ref.args, + ) { + continue; + } + + let is_match = + infcx.probe(|_| match_candidate(selcx, obligation, data, true, |_, _| {}).is_ok()); + + if is_match { + if candidate.is_some() { + return Err(EvaluationFailure::Ambiguous); + } else { + candidate = Some(data); + } + } + } + + if kind != ty::Projection { + break; + } + + consider_ty = alias_ty.self_ty(); + } + + if let Some(data) = candidate { + Ok(match_candidate(selcx, obligation, data, true, |_, _| {}) + .expect("candidate matched before, so it should match again")) + } else { + Err(EvaluationFailure::NoSolution) + } +} + fn evaluate_host_effect_from_builtin_impls<'tcx>( selcx: &mut SelectionContext<'_, 'tcx>, obligation: &HostEffectObligation<'tcx>, ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { match selcx.tcx().as_lang_item(obligation.predicate.def_id()) { Some(LangItem::Destruct) => evaluate_host_effect_for_destruct_goal(selcx, obligation), + Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce) => { + evaluate_host_effect_for_fn_goal(selcx, obligation) + } _ => Err(EvaluationFailure::NoSolution), } } @@ -252,20 +321,20 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( let self_ty = obligation.predicate.self_ty(); let const_conditions = match *self_ty.kind() { - // `ManuallyDrop` is trivially `~const Destruct` as we do not run any drop glue on it. + // `ManuallyDrop` is trivially `[const] Destruct` as we do not run any drop glue on it. ty::Adt(adt_def, _) if adt_def.is_manually_drop() => thin_vec![], - // An ADT is `~const Destruct` only if all of the fields are, - // *and* if there is a `Drop` impl, that `Drop` impl is also `~const`. + // An ADT is `[const] Destruct` only if all of the fields are, + // *and* if there is a `Drop` impl, that `Drop` impl is also `[const]`. ty::Adt(adt_def, args) => { let mut const_conditions: ThinVec<_> = adt_def .all_fields() .map(|field| ty::TraitRef::new(tcx, destruct_def_id, [field.ty(tcx, args)])) .collect(); match adt_def.destructor(tcx).map(|dtor| tcx.constness(dtor.did)) { - // `Drop` impl exists, but it's not const. Type cannot be `~const Destruct`. + // `Drop` impl exists, but it's not const. Type cannot be `[const] Destruct`. Some(hir::Constness::NotConst) => return Err(EvaluationFailure::NoSolution), - // `Drop` impl exists, and it's const. Require `Ty: ~const Drop` to hold. + // `Drop` impl exists, and it's const. Require `Ty: [const] Drop` to hold. Some(hir::Constness::Const) => { let drop_def_id = tcx.require_lang_item(LangItem::Drop, obligation.cause.span); let drop_trait_ref = ty::TraitRef::new(tcx, drop_def_id, [self_ty]); @@ -285,7 +354,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( tys.iter().map(|field_ty| ty::TraitRef::new(tcx, destruct_def_id, [field_ty])).collect() } - // Trivially implement `~const Destruct` + // Trivially implement `[const] Destruct` ty::Bool | ty::Char | ty::Int(..) @@ -300,14 +369,14 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( | ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_)) | ty::Error(_) => thin_vec![], - // Coroutines and closures could implement `~const Drop`, + // Coroutines and closures could implement `[const] Drop`, // but they don't really need to right now. ty::Closure(_, _) | ty::CoroutineClosure(_, _) | ty::Coroutine(_, _) | ty::CoroutineWitness(_, _) => return Err(EvaluationFailure::NoSolution), - // FIXME(unsafe_binders): Unsafe binders could implement `~const Drop` + // FIXME(unsafe_binders): Unsafe binders could implement `[const] Drop` // if their inner type implements it. ty::UnsafeBinder(_) => return Err(EvaluationFailure::NoSolution), @@ -333,7 +402,52 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( .collect()) } -fn evaluate_host_effect_from_selection_candiate<'tcx>( +// NOTE: Keep this in sync with `extract_fn_def_from_const_callable` in the new solver. +fn evaluate_host_effect_for_fn_goal<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { + let tcx = selcx.tcx(); + let self_ty = obligation.predicate.self_ty(); + + let (def, args) = match *self_ty.kind() { + ty::FnDef(def, args) => (def, args), + + // We may support function pointers at some point in the future + ty::FnPtr(..) => return Err(EvaluationFailure::NoSolution), + + // Closures could implement `[const] Fn`, + // but they don't really need to right now. + ty::Closure(..) | ty::CoroutineClosure(_, _) => { + return Err(EvaluationFailure::NoSolution); + } + + // Everything else needs explicit impls or cannot have an impl + _ => return Err(EvaluationFailure::NoSolution), + }; + + match tcx.constness(def) { + hir::Constness::Const => Ok(tcx + .const_conditions(def) + .instantiate(tcx, args) + .into_iter() + .map(|(c, span)| { + let code = ObligationCauseCode::WhereClause(def, span); + let cause = + ObligationCause::new(obligation.cause.span, obligation.cause.body_id, code); + Obligation::new( + tcx, + cause, + obligation.param_env, + c.to_host_effect_clause(tcx, obligation.predicate.constness), + ) + }) + .collect()), + hir::Constness::NotConst => Err(EvaluationFailure::NoSolution), + } +} + +fn evaluate_host_effect_from_selection_candidate<'tcx>( selcx: &mut SelectionContext<'_, 'tcx>, obligation: &HostEffectObligation<'tcx>, ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 951dfb879ae..2b5a41ef5a7 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -11,8 +11,10 @@ use rustc_infer::traits::{ use rustc_middle::bug; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode}; -use thin_vec::ThinVec; +use rustc_middle::ty::{ + self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode, may_use_unstable_feature, +}; +use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, debug_span, instrument}; use super::effects::{self, HostEffectObligation}; @@ -20,7 +22,7 @@ use super::project::{self, ProjectAndUnifyResult}; use super::select::SelectionContext; use super::{ EvaluationResult, FulfillmentError, FulfillmentErrorCode, PredicateObligation, - ScrubbedTraitError, Unimplemented, const_evaluatable, wf, + ScrubbedTraitError, const_evaluatable, wf, }; use crate::error_reporting::InferCtxtErrorExt; use crate::infer::{InferCtxt, TyOrConstInferVar}; @@ -336,7 +338,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { let infcx = self.selcx.infcx; if sizedness_fast_path(infcx.tcx, obligation.predicate) { - return ProcessResult::Changed(thin_vec::thin_vec![]); + return ProcessResult::Changed(thin_vec![]); } if obligation.predicate.has_aliases() { @@ -404,6 +406,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::AliasRelate(..) => { bug!("AliasRelate is only used by the new solver") } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) => { + unreachable!("unexpected higher ranked `UnstableFeature` goal") + } }, Some(pred) => match pred { ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { @@ -456,7 +461,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::DynCompatible(trait_def_id) => { if !self.selcx.tcx().is_dyn_compatible(trait_def_id) { - ProcessResult::Error(FulfillmentErrorCode::Select(Unimplemented)) + ProcessResult::Error(FulfillmentErrorCode::Select( + SelectionError::Unimplemented, + )) } else { ProcessResult::Changed(Default::default()) } @@ -507,7 +514,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct), ty::ConstKind::Param(param_ct) => { - param_ct.find_ty_from_env(obligation.param_env) + param_ct.find_const_ty_from_env(obligation.param_env) } }; @@ -541,6 +548,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => { + if term.is_trivially_wf(self.selcx.tcx()) { + return ProcessResult::Changed(thin_vec![]); + } + match wf::obligations( self.selcx.infcx, obligation.param_env, @@ -761,6 +772,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { + if may_use_unstable_feature(self.selcx.infcx, obligation.param_env, symbol) { + ProcessResult::Changed(Default::default()) + } else { + ProcessResult::Unchanged + } + } }, } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 999ef97683c..91c41544f78 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -36,8 +36,8 @@ use rustc_middle::ty::{ self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypingMode, Upcast, }; +use rustc_span::Span; use rustc_span::def_id::DefId; -use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; pub use self::coherence::{ @@ -481,7 +481,7 @@ pub enum EvaluateConstErr { /// some unevaluated constant with either generic parameters or inference variables in its /// generic arguments. HasGenericsOrInfers, - /// The type this constant evalauted to is not valid for use in const generics. This should + /// The type this constant evaluated to is not valid for use in const generics. This should /// always result in an error when checking the constant is correctly typed for the parameter /// it is an argument to, so a bug is delayed when encountering this. InvalidConstParamTy(ErrorGuaranteed), @@ -644,7 +644,9 @@ pub fn try_evaluate_const<'tcx>( 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) { + // FIXME: `def_span` will point at the definition of this const; ideally, we'd point at + // where it gets used as a const generic. + match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, tcx.def_span(uv.def)) { Ok(Ok(val)) => Ok(ty::Const::new_value( tcx, val, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 6dd80551980..28b5b7cf391 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -84,9 +84,6 @@ impl<'tcx> ProjectionCandidateSet<'tcx> { // was discarded -- this could be because of ambiguity, or because // a higher-priority candidate is already there. fn push_candidate(&mut self, candidate: ProjectionCandidate<'tcx>) -> bool { - use self::ProjectionCandidate::*; - use self::ProjectionCandidateSet::*; - // This wacky variable is just used to try and // make code readable and avoid confusing paths. // It is assigned a "value" of `()` only on those @@ -98,12 +95,12 @@ impl<'tcx> ProjectionCandidateSet<'tcx> { let convert_to_ambiguous; match self { - None => { - *self = Single(candidate); + ProjectionCandidateSet::None => { + *self = ProjectionCandidateSet::Single(candidate); return true; } - Single(current) => { + ProjectionCandidateSet::Single(current) => { // Duplicates can happen inside ParamEnv. In the case, we // perform a lazy deduplication. if current == &candidate { @@ -118,16 +115,18 @@ impl<'tcx> ProjectionCandidateSet<'tcx> { // clauses are the safer choice. See the comment on // `select::SelectionCandidate` and #21974 for more details. match (current, candidate) { - (ParamEnv(..), ParamEnv(..)) => convert_to_ambiguous = (), - (ParamEnv(..), _) => return false, - (_, ParamEnv(..)) => bug!( + (ProjectionCandidate::ParamEnv(..), ProjectionCandidate::ParamEnv(..)) => { + convert_to_ambiguous = () + } + (ProjectionCandidate::ParamEnv(..), _) => return false, + (_, ProjectionCandidate::ParamEnv(..)) => bug!( "should never prefer non-param-env candidates over param-env candidates" ), (_, _) => convert_to_ambiguous = (), } } - Ambiguous | Error(..) => { + ProjectionCandidateSet::Ambiguous | ProjectionCandidateSet::Error(..) => { return false; } } @@ -135,7 +134,7 @@ impl<'tcx> ProjectionCandidateSet<'tcx> { // We only ever get here when we moved from a single candidate // to ambiguous. let () = convert_to_ambiguous; - *self = Ambiguous; + *self = ProjectionCandidateSet::Ambiguous; false } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 18010603286..3b549244431 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -103,10 +103,7 @@ where let region_constraint_data = infcx.take_and_reset_region_constraints(); let region_constraints = query_response::make_query_region_constraints( infcx.tcx, - region_obligations - .iter() - .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())) - .map(|(ty, r, cc)| (infcx.resolve_vars_if_possible(ty), r, cc)), + region_obligations, ®ion_constraint_data, ); 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 e294f7839aa..7540cbe3fd1 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 @@ -110,6 +110,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::NormalizesTo(..) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::AliasRelate(..) => {} // We need to search through *all* WellFormed predicates diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs index 18971c47831..22eeb285b37 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -21,19 +21,9 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { if let ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) = key.value.predicate.kind().skip_binder() + && term.is_trivially_wf(tcx) { - match term.as_type()?.kind() { - ty::Param(_) - | ty::Bool - | ty::Char - | ty::Int(_) - | ty::Float(_) - | ty::Str - | ty::Uint(_) => { - return Some(()); - } - _ => {} - } + return Some(()); } None 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 81ce58a93fa..cc188a280aa 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -19,7 +19,7 @@ use rustc_middle::{bug, span_bug}; use tracing::{debug, instrument, trace}; use super::SelectionCandidate::*; -use super::{BuiltinImplConditions, SelectionCandidateSet, SelectionContext, TraitObligationStack}; +use super::{SelectionCandidateSet, SelectionContext, TraitObligationStack}; use crate::traits::util; impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { @@ -75,27 +75,29 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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); + self.assemble_builtin_copy_clone_candidate( + obligation.predicate.self_ty().skip_binder(), + &mut candidates, + ); } Some(LangItem::DiscriminantKind) => { // `DiscriminantKind` is automatically implemented for every type. - candidates.vec.push(BuiltinCandidate { has_nested: false }); + candidates.vec.push(BuiltinCandidate); } Some(LangItem::PointeeTrait) => { // `Pointee` is automatically implemented for every type. - candidates.vec.push(BuiltinCandidate { has_nested: false }); + candidates.vec.push(BuiltinCandidate); } Some(LangItem::Sized) => { self.assemble_builtin_sized_candidate( - obligation, + obligation.predicate.self_ty().skip_binder(), &mut candidates, SizedTraitKind::Sized, ); } Some(LangItem::MetaSized) => { self.assemble_builtin_sized_candidate( - obligation, + obligation.predicate.self_ty().skip_binder(), &mut candidates, SizedTraitKind::MetaSized, ); @@ -357,15 +359,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PolyTraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - let self_ty = obligation.self_ty().skip_binder(); - // gen constructs get lowered to a special kind of coroutine that - // should directly `impl FusedIterator`. - if let ty::Coroutine(did, ..) = self_ty.kind() - && self.tcx().coroutine_is_gen(*did) - { - debug!(?self_ty, ?obligation, "assemble_fused_iterator_candidates",); - - candidates.vec.push(BuiltinCandidate { has_nested: false }); + if self.coroutine_is_gen(obligation.self_ty().skip_binder()) { + candidates.vec.push(BuiltinCandidate); } } @@ -810,7 +805,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { hir::Movability::Movable => { // Movable coroutines are always `Unpin`, so add an // unconditional builtin candidate. - candidates.vec.push(BuiltinCandidate { has_nested: false }); + candidates.vec.push(BuiltinCandidate); } } } @@ -1113,45 +1108,164 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - /// Assembles the `Sized` and `MetaSized` traits which are built-in to the language itself. + /// Assembles `Copy` and `Clone` candidates for built-in types with no libcore-defined + /// `Copy` or `Clone` impls. #[instrument(level = "debug", skip(self, candidates))] - fn assemble_builtin_sized_candidate( + fn assemble_builtin_copy_clone_candidate( &mut self, - obligation: &PolyTraitObligation<'tcx>, + self_ty: Ty<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, - sizedness: SizedTraitKind, ) { - match self.sizedness_conditions(obligation, sizedness) { - BuiltinImplConditions::Where(nested) => { - candidates - .vec - .push(SizedCandidate { has_nested: !nested.skip_binder().is_empty() }); + match *self_ty.kind() { + // These impls are built-in because we cannot express sufficiently + // generic impls in libcore. + ty::FnDef(..) + | ty::FnPtr(..) + | ty::Error(_) + | ty::Tuple(..) + | ty::CoroutineWitness(..) + | ty::Pat(..) => { + candidates.vec.push(BuiltinCandidate); + } + + // Implementations provided in libcore. + ty::Uint(_) + | ty::Int(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Ref(_, _, hir::Mutability::Not) + | ty::Array(..) => {} + + // FIXME(unsafe_binder): Should we conditionally + // (i.e. universally) implement copy/clone? + ty::UnsafeBinder(_) => {} + + // Not `Sized`, which is a supertrait of `Copy`/`Clone`. + ty::Dynamic(..) | ty::Str | ty::Slice(..) | ty::Foreign(..) => {} + + // Not `Copy` or `Clone` by design. + ty::Ref(_, _, hir::Mutability::Mut) => {} + + ty::Coroutine(coroutine_def_id, args) => { + match self.tcx().coroutine_movability(coroutine_def_id) { + hir::Movability::Static => {} + hir::Movability::Movable => { + if self.tcx().features().coroutine_clone() { + let resolved_upvars = + self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); + let resolved_witness = + self.infcx.shallow_resolve(args.as_coroutine().witness()); + if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() { + // Not yet resolved. + candidates.ambiguous = true; + } else { + candidates.vec.push(BuiltinCandidate); + } + } + } + } + } + + ty::Closure(_, args) => { + let resolved_upvars = + self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty()); + if resolved_upvars.is_ty_var() { + // Not yet resolved. + candidates.ambiguous = true; + } else { + candidates.vec.push(BuiltinCandidate); + } + } + + ty::CoroutineClosure(_, args) => { + let resolved_upvars = + self.infcx.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty()); + if resolved_upvars.is_ty_var() { + // Not yet resolved. + candidates.ambiguous = true; + } else { + candidates.vec.push(BuiltinCandidate); + } } - BuiltinImplConditions::None => {} - BuiltinImplConditions::Ambiguous => { + + // Fallback to whatever user-defined impls or param-env clauses exist in this case. + ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {} + + ty::Infer(ty::TyVar(_)) => { candidates.ambiguous = true; } + + // Only appears when assembling higher-ranked `for<T> T: Clone`. + ty::Bound(..) => {} + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); + } } } - /// Assembles the trait which are built-in to the language itself: - /// e.g. `Copy` and `Clone`. + /// Assembles the `Sized` and `MetaSized` traits which are built-in to the language itself. #[instrument(level = "debug", skip(self, candidates))] - fn assemble_builtin_bound_candidates( + fn assemble_builtin_sized_candidate( &mut self, - conditions: BuiltinImplConditions<'tcx>, + self_ty: Ty<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, + sizedness: SizedTraitKind, ) { - match conditions { - BuiltinImplConditions::Where(nested) => { - candidates - .vec - .push(BuiltinCandidate { has_nested: !nested.skip_binder().is_empty() }); + match *self_ty.kind() { + // Always sized. + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::RawPtr(..) + | ty::Char + | ty::Ref(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Array(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Never + | ty::Error(_) => { + candidates.vec.push(SizedCandidate); + } + + // Conditionally `Sized`. + ty::Tuple(..) | ty::Pat(..) | ty::Adt(..) | ty::UnsafeBinder(_) => { + candidates.vec.push(SizedCandidate); } - BuiltinImplConditions::None => {} - BuiltinImplConditions::Ambiguous => { + + // `MetaSized` but not `Sized`. + ty::Str | ty::Slice(_) | ty::Dynamic(..) => match sizedness { + SizedTraitKind::Sized => {} + SizedTraitKind::MetaSized => { + candidates.vec.push(SizedCandidate); + } + }, + + // Not `MetaSized` or `Sized`. + ty::Foreign(..) => {} + + ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => {} + + ty::Infer(ty::TyVar(_)) => { candidates.ambiguous = true; } + + // Only appears when assembling higher-ranked `for<T> T: Sized`. + ty::Bound(..) => {} + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); + } } } @@ -1160,7 +1274,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _obligation: &PolyTraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - candidates.vec.push(BuiltinCandidate { has_nested: false }); + candidates.vec.push(BuiltinCandidate); } fn assemble_candidate_for_tuple( @@ -1171,7 +1285,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); match self_ty.kind() { ty::Tuple(_) => { - candidates.vec.push(BuiltinCandidate { has_nested: false }); + candidates.vec.push(BuiltinCandidate); } ty::Infer(ty::TyVar(_)) => { candidates.ambiguous = true; @@ -1215,7 +1329,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = self.infcx.resolve_vars_if_possible(obligation.self_ty()); match self_ty.skip_binder().kind() { - ty::FnPtr(..) => candidates.vec.push(BuiltinCandidate { has_nested: false }), + ty::FnPtr(..) => candidates.vec.push(BuiltinCandidate), ty::Bool | ty::Char | ty::Int(_) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 80f71c78993..ee8cef20279 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -11,25 +11,22 @@ use std::ops::ControlFlow; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; -use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk}; +use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk}; use rustc_infer::traits::ObligationCauseCode; use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData}; -use rustc_middle::ty::{ - self, GenericArgsRef, Region, SizedTraitKind, Ty, TyCtxt, Upcast, elaborate, -}; +use rustc_middle::ty::{self, GenericArgsRef, Region, SizedTraitKind, Ty, TyCtxt, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use thin_vec::thin_vec; use tracing::{debug, instrument}; use super::SelectionCandidate::{self, *}; -use super::{BuiltinImplConditions, PredicateObligations, SelectionContext}; +use super::{PredicateObligations, SelectionContext}; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::util::{self, closure_trait_ref_and_return_type}; use crate::traits::{ ImplSource, ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause, - PolyTraitObligation, PredicateObligation, Selection, SelectionError, SignatureMismatch, - TraitDynIncompatible, TraitObligation, Unimplemented, + PolyTraitObligation, PredicateObligation, Selection, SelectionError, TraitObligation, }; impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { @@ -40,13 +37,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidate: SelectionCandidate<'tcx>, ) -> Result<Selection<'tcx>, SelectionError<'tcx>> { Ok(match candidate { - SizedCandidate { has_nested } => { - let data = self.confirm_builtin_candidate(obligation, has_nested); + SizedCandidate => { + let data = self.confirm_builtin_candidate(obligation); ImplSource::Builtin(BuiltinImplSource::Misc, data) } - BuiltinCandidate { has_nested } => { - let data = self.confirm_builtin_candidate(obligation, has_nested); + BuiltinCandidate => { + let data = self.confirm_builtin_candidate(obligation); ImplSource::Builtin(BuiltinImplSource::Misc, data) } @@ -176,7 +173,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let candidate = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, - HigherRankedType, + BoundRegionConversionTime::HigherRankedType, candidate, ); let mut obligations = PredicateObligations::new(); @@ -194,7 +191,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .at(&obligation.cause, obligation.param_env) .eq(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate) .map(|InferOk { obligations, .. }| obligations) - .map_err(|_| Unimplemented)?, + .map_err(|_| SelectionError::Unimplemented)?, ); // FIXME(compiler-errors): I don't think this is needed. @@ -252,50 +249,53 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + #[instrument(level = "debug", skip(self), ret)] fn confirm_builtin_candidate( &mut self, obligation: &PolyTraitObligation<'tcx>, - has_nested: bool, ) -> PredicateObligations<'tcx> { - debug!(?obligation, ?has_nested, "confirm_builtin_candidate"); - + debug!(?obligation, "confirm_builtin_candidate"); let tcx = self.tcx(); - let obligations = if has_nested { - let trait_def = obligation.predicate.def_id(); - let conditions = match tcx.as_lang_item(trait_def) { - Some(LangItem::Sized) => { - self.sizedness_conditions(obligation, SizedTraitKind::Sized) - } - Some(LangItem::MetaSized) => { - self.sizedness_conditions(obligation, SizedTraitKind::MetaSized) - } - Some(LangItem::PointeeSized) => { - bug!("`PointeeSized` is removing during lowering"); + let trait_def = obligation.predicate.def_id(); + let self_ty = self.infcx.shallow_resolve( + self.infcx.enter_forall_and_leak_universe(obligation.predicate.self_ty()), + ); + let types = match tcx.as_lang_item(trait_def) { + Some(LangItem::Sized) => self.sizedness_conditions(self_ty, SizedTraitKind::Sized), + Some(LangItem::MetaSized) => { + self.sizedness_conditions(self_ty, SizedTraitKind::MetaSized) + } + Some(LangItem::PointeeSized) => { + bug!("`PointeeSized` is removing during lowering"); + } + Some(LangItem::Copy | LangItem::Clone) => self.copy_clone_conditions(self_ty), + Some(LangItem::FusedIterator) => { + if self.coroutine_is_gen(self_ty) { + ty::Binder::dummy(vec![]) + } else { + unreachable!("tried to assemble `FusedIterator` for non-gen coroutine"); } - 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); - }; - let types = self.infcx.enter_forall_and_leak_universe(types); - - let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); - self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def, - types, - ) - } else { - PredicateObligations::new() + } + Some( + LangItem::Destruct + | LangItem::DiscriminantKind + | LangItem::FnPtrTrait + | LangItem::PointeeTrait + | LangItem::Tuple + | LangItem::Unpin, + ) => ty::Binder::dummy(vec![]), + other => bug!("unexpected builtin trait {trait_def:?} ({other:?})"), }; + let types = self.infcx.enter_forall_and_leak_universe(types); - debug!(?obligations); - - obligations + let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); + self.collect_predicates_for_types( + obligation.param_env, + cause, + obligation.recursion_depth + 1, + trait_def, + types, + ) } #[instrument(level = "debug", skip(self))] @@ -374,7 +374,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env) } let Some(assume) = rustc_transmute::Assume::from_const(self.infcx.tcx, assume) else { - return Err(Unimplemented); + return Err(SelectionError::Unimplemented); }; let dst = predicate.trait_ref.args.type_at(0); @@ -386,7 +386,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { transmute_env.is_transmutable(rustc_transmute::Types { dst, src }, assume); let fully_flattened = match maybe_transmutable { - Answer::No(_) => Err(Unimplemented)?, + Answer::No(_) => Err(SelectionError::Unimplemented)?, Answer::If(cond) => flatten_answer_tree(self.tcx(), obligation, cond, assume), Answer::Yes => PredicateObligations::new(), }; @@ -409,6 +409,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty)); + let self_ty = self.infcx.enter_forall_and_leak_universe(self_ty); let types = self.constituent_types_for_ty(self_ty)?; let types = self.infcx.enter_forall_and_leak_universe(types); @@ -500,7 +501,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }); let object_trait_ref = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, - HigherRankedType, + BoundRegionConversionTime::HigherRankedType, object_trait_ref, ); let object_trait_ref = object_trait_ref.with_self_ty(self.tcx(), self_ty); @@ -513,7 +514,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let upcast_trait_ref = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, - HigherRankedType, + BoundRegionConversionTime::HigherRankedType, unnormalized_upcast_trait_ref, ); let upcast_trait_ref = normalize_with_depth_to( @@ -530,7 +531,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .at(&obligation.cause, obligation.param_env) .eq(DefineOpaqueTypes::No, trait_predicate.trait_ref, upcast_trait_ref) .map(|InferOk { obligations, .. }| obligations) - .map_err(|_| Unimplemented)?, + .map_err(|_| SelectionError::Unimplemented)?, ); // Check supertraits hold. This is so that their associated type bounds @@ -905,7 +906,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let goal_kind = self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap(); - // If we have not yet determiend the `ClosureKind` of the closure or coroutine-closure, + // If we have not yet determined the `ClosureKind` of the closure or coroutine-closure, // then additionally register an `AsyncFnKindHelper` goal which will fail if the kind // is constrained to an insufficient type later on. if let Some(closure_kind) = self.infcx.shallow_resolve(kind_ty).to_opt_closure_kind() { @@ -962,7 +963,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> { let found_trait_ref = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, - HigherRankedType, + BoundRegionConversionTime::HigherRankedType, found_trait_ref, ); // Normalize the obligation and expected trait refs together, because why not @@ -986,7 +987,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations }) .map_err(|terr| { - SignatureMismatch(Box::new(SignatureMismatchData { + SelectionError::SignatureMismatch(Box::new(SignatureMismatchData { expected_trait_ref: obligation_trait_ref, found_trait_ref, terr, @@ -1090,7 +1091,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .infcx .at(&obligation.cause, obligation.param_env) .sup(DefineOpaqueTypes::Yes, target, source_trait) - .map_err(|_| Unimplemented)?; + .map_err(|_| SelectionError::Unimplemented)?; // Register one obligation for 'a: 'b. let outlives = ty::OutlivesPredicate(r_a, r_b); @@ -1109,7 +1110,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (_, &ty::Dynamic(data, r, ty::Dyn)) => { let mut object_dids = data.auto_traits().chain(data.principal_def_id()); if let Some(did) = object_dids.find(|did| !tcx.is_dyn_compatible(*did)) { - return Err(TraitDynIncompatible(did)); + return Err(SelectionError::TraitDynIncompatible(did)); } let predicate_to_obligation = |predicate| { @@ -1148,38 +1149,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::ClauseKind::TypeOutlives(outlives).upcast(tcx), )); - // Require that all AFIT will return something that can be coerced into `dyn*` - // -- a shim will be responsible for doing the actual coercion to `dyn*`. - if let Some(principal) = data.principal() { - for supertrait in - elaborate::supertraits(tcx, principal.with_self_ty(tcx, source)) - { - if tcx.is_trait_alias(supertrait.def_id()) { - continue; - } - - for &assoc_item in tcx.associated_item_def_ids(supertrait.def_id()) { - if !tcx.is_impl_trait_in_trait(assoc_item) { - continue; - } - - // RPITITs with `Self: Sized` don't need to be checked. - if tcx.generics_require_sized_self(assoc_item) { - continue; - } - - let pointer_like_goal = pointer_like_goal_for_rpitit( - tcx, - supertrait, - assoc_item, - &obligation.cause, - ); - - nested.push(predicate_to_obligation(pointer_like_goal.upcast(tcx))); - } - } - } - ImplSource::Builtin(BuiltinImplSource::Misc, nested) } @@ -1189,7 +1158,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .infcx .at(&obligation.cause, obligation.param_env) .eq(DefineOpaqueTypes::Yes, b, a) - .map_err(|_| Unimplemented)?; + .map_err(|_| SelectionError::Unimplemented)?; ImplSource::Builtin(BuiltinImplSource::Misc, obligations) } @@ -1198,7 +1167,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (&ty::Adt(def, args_a), &ty::Adt(_, args_b)) => { let unsizing_params = tcx.unsizing_params_for_adt(def.did()); if unsizing_params.is_empty() { - return Err(Unimplemented); + return Err(SelectionError::Unimplemented); } let tail_field = def.non_enum_variant().tail(); @@ -1237,7 +1206,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .infcx .at(&obligation.cause, obligation.param_env) .eq(DefineOpaqueTypes::Yes, target, new_struct) - .map_err(|_| Unimplemented)?; + .map_err(|_| SelectionError::Unimplemented)?; nested.extend(obligations); // Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate. @@ -1345,46 +1314,3 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(BuiltinImplSource::Misc, obligations) } } - -/// Compute a goal that some RPITIT (right now, only RPITITs corresponding to Futures) -/// implements the `PointerLike` trait, which is a requirement for the RPITIT to be -/// coercible to `dyn* Future`, which is itself a requirement for the RPITIT's parent -/// trait to be coercible to `dyn Trait`. -/// -/// We do this given a supertrait's substitutions, and then augment the substitutions -/// with bound variables to compute the goal universally. Given that `PointerLike` has -/// no region requirements (at least for the built-in pointer types), this shouldn't -/// *really* matter, but it is the best choice for soundness. -fn pointer_like_goal_for_rpitit<'tcx>( - tcx: TyCtxt<'tcx>, - supertrait: ty::PolyTraitRef<'tcx>, - rpitit_item: DefId, - cause: &ObligationCause<'tcx>, -) -> ty::PolyTraitRef<'tcx> { - let mut bound_vars = supertrait.bound_vars().to_vec(); - - let args = supertrait.skip_binder().args.extend_to(tcx, rpitit_item, |arg, _| match arg.kind { - ty::GenericParamDefKind::Lifetime => { - let kind = ty::BoundRegionKind::Named(arg.def_id, tcx.item_name(arg.def_id)); - bound_vars.push(ty::BoundVariableKind::Region(kind)); - ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, - ) - .into() - } - ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => { - unreachable!() - } - }); - - ty::Binder::bind_with_vars( - ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::PointerLike, cause.span), - [Ty::new_projection_from_args(tcx, rpitit_item, args)], - ), - tcx.mk_bound_variable_kinds(&bound_vars), - ) -} diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 9c0ccb26e53..10bcf861d35 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -28,7 +28,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{ self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, SizedTraitKind, Ty, TyCtxt, - TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate, + TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate, may_use_unstable_feature, }; use rustc_span::{Symbol, sym}; use tracing::{debug, instrument, trace}; @@ -39,7 +39,7 @@ use super::coherence::{self, Conflict}; use super::project::ProjectionTermObligation; use super::util::closure_trait_ref_and_return_type; use super::{ - ImplDerivedCause, Normalized, Obligation, ObligationCause, ObligationCauseCode, Overflow, + ImplDerivedCause, Normalized, Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation, Selection, SelectionError, SelectionResult, TraitQueryMode, const_evaluatable, project, util, wf, }; @@ -48,9 +48,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt as _; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt}; -use crate::traits::{ - EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects, sizedness_fast_path, -}; +use crate::traits::{EvaluateConstErr, ProjectionCacheKey, effects, sizedness_fast_path}; mod _match; mod candidate_assembly; @@ -190,18 +188,6 @@ struct EvaluatedCandidate<'tcx> { evaluation: EvaluationResult, } -/// When does the builtin impl for `T: Trait` apply? -#[derive(Debug)] -enum BuiltinImplConditions<'tcx> { - /// The impl is conditional on `T1, T2, ...: Trait`. - Where(ty::Binder<'tcx, Vec<Ty<'tcx>>>), - /// There is no built-in impl. There may be some other - /// candidate (a where-clause or user-defined impl). - None, - /// It is unknown whether there is an impl. - Ambiguous, -} - impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> { SelectionContext { @@ -454,8 +440,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) } Ok(_) => Ok(None), - Err(OverflowError::Canonical) => Err(Overflow(OverflowError::Canonical)), - Err(OverflowError::Error(e)) => Err(Overflow(OverflowError::Error(e))), + Err(OverflowError::Canonical) => { + Err(SelectionError::Overflow(OverflowError::Canonical)) + } + Err(OverflowError::Error(e)) => { + Err(SelectionError::Overflow(OverflowError::Error(e))) + } }) .flat_map(Result::transpose) .collect::<Result<Vec<_>, _>>()?; @@ -479,7 +469,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?stack.obligation.predicate, "found error type in predicate, treating as ambiguous"); Ok(None) } else { - Err(Unimplemented) + Err(SelectionError::Unimplemented) } } else { let has_non_region_infer = stack.obligation.predicate.has_non_region_infer(); @@ -660,6 +650,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => { + if term.is_trivially_wf(self.tcx()) { + return Ok(EvaluatedToOk); + } + // So, there is a bit going on here. First, `WellFormed` predicates // are coinductive, like trait predicates with auto traits. // This means that we need to detect if we have recursively @@ -838,6 +832,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { + if may_use_unstable_feature(self.infcx, obligation.param_env, symbol) { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToAmbig) + } + } + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { match const_evaluatable::is_const_evaluatable( self.infcx, @@ -979,7 +981,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct), ty::ConstKind::Param(param_ct) => { - param_ct.find_ty_from_env(obligation.param_env) + param_ct.find_const_ty_from_env(obligation.param_env) } }; @@ -1222,7 +1224,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match self.candidate_from_obligation(stack) { Ok(Some(c)) => self.evaluate_candidate(stack, &c), Ok(None) => Ok(EvaluatedToAmbig), - Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical), + Err(SelectionError::Overflow(OverflowError::Canonical)) => { + Err(OverflowError::Canonical) + } Err(..) => Ok(EvaluatedToErr), } } @@ -1536,7 +1540,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Some(res); } else if cfg!(debug_assertions) { match infcx.selection_cache.get(&(param_env, pred), tcx) { - None | Some(Err(Overflow(OverflowError::Canonical))) => {} + None | Some(Err(SelectionError::Overflow(OverflowError::Canonical))) => {} res => bug!("unexpected local cache result: {res:?}"), } } @@ -1592,7 +1596,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if self.can_use_global_caches(param_env, cache_fresh_trait_pred) { - if let Err(Overflow(OverflowError::Canonical)) = candidate { + if let Err(SelectionError::Overflow(OverflowError::Canonical)) = candidate { // Don't cache overflow globally; we only produce this in certain modes. } else { debug!(?pred, ?candidate, "insert_candidate_cache global"); @@ -1826,7 +1830,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // We prefer `Sized` candidates over everything. let mut sized_candidates = - candidates.iter().filter(|c| matches!(c.candidate, SizedCandidate { has_nested: _ })); + candidates.iter().filter(|c| matches!(c.candidate, SizedCandidate)); if let Some(sized_candidate) = sized_candidates.next() { // There should only ever be a single sized candidate // as they would otherwise overlap. @@ -1978,8 +1982,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // Don't use impl candidates which overlap with other candidates. // This should pretty much only ever happen with malformed impls. if candidates.iter().all(|c| match c.candidate { - SizedCandidate { has_nested: _ } - | BuiltinCandidate { has_nested: _ } + SizedCandidate + | BuiltinCandidate | TransmutabilityCandidate | AutoImplCandidate | ClosureCandidate { .. } @@ -2096,14 +2100,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { impl<'tcx> SelectionContext<'_, 'tcx> { fn sizedness_conditions( &mut self, - obligation: &PolyTraitObligation<'tcx>, + self_ty: Ty<'tcx>, sizedness: SizedTraitKind, - ) -> BuiltinImplConditions<'tcx> { - use self::BuiltinImplConditions::{Ambiguous, None, Where}; - - // NOTE: binder moved to (*) - let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); - + ) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> { match self_ty.kind() { ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Uint(_) @@ -2121,60 +2120,44 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never - | ty::Dynamic(_, _, ty::DynStar) - | ty::Error(_) => { - // safe for everything - Where(ty::Binder::dummy(Vec::new())) - } + | ty::Error(_) => ty::Binder::dummy(vec![]), ty::Str | ty::Slice(_) | ty::Dynamic(..) => match sizedness { - SizedTraitKind::Sized => None, - SizedTraitKind::MetaSized => Where(ty::Binder::dummy(Vec::new())), + SizedTraitKind::Sized => unreachable!("tried to assemble `Sized` for unsized type"), + SizedTraitKind::MetaSized => ty::Binder::dummy(vec![]), }, - ty::Foreign(..) => None, + ty::Foreign(..) => unreachable!("tried to assemble `Sized` for unsized type"), - ty::Tuple(tys) => Where( - obligation.predicate.rebind(tys.last().map_or_else(Vec::new, |&last| vec![last])), - ), + ty::Tuple(tys) => { + ty::Binder::dummy(tys.last().map_or_else(Vec::new, |&last| vec![last])) + } - ty::Pat(ty, _) => Where(obligation.predicate.rebind(vec![*ty])), + ty::Pat(ty, _) => ty::Binder::dummy(vec![*ty]), ty::Adt(def, args) => { if let Some(crit) = def.sizedness_constraint(self.tcx(), sizedness) { - // (*) binder moved here - Where(obligation.predicate.rebind(vec![crit.instantiate(self.tcx(), args)])) + ty::Binder::dummy(vec![crit.instantiate(self.tcx(), args)]) } else { - Where(ty::Binder::dummy(Vec::new())) + ty::Binder::dummy(vec![]) } } - // FIXME(unsafe_binders): This binder needs to be squashed - ty::UnsafeBinder(binder_ty) => Where(binder_ty.map_bound(|ty| vec![ty])), + ty::UnsafeBinder(binder_ty) => binder_ty.map_bound(|ty| vec![ty]), - ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => None, - ty::Infer(ty::TyVar(_)) => Ambiguous, - - // We can make this an ICE if/once we actually instantiate the trait obligation eagerly. - ty::Bound(..) => None, - - ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); + ty::Alias(..) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) + | ty::Bound(..) => { + bug!("asked to assemble `Sized` of unexpected type: {:?}", self_ty); } } } - fn copy_clone_conditions( - &mut self, - obligation: &PolyTraitObligation<'tcx>, - ) -> BuiltinImplConditions<'tcx> { - // NOTE: binder moved to (*) - let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); - - use self::BuiltinImplConditions::{Ambiguous, None, Where}; - + fn copy_clone_conditions(&mut self, self_ty: Ty<'tcx>) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> { match *self_ty.kind() { - ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => Where(ty::Binder::dummy(Vec::new())), + ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => ty::Binder::dummy(vec![]), ty::Uint(_) | ty::Int(_) @@ -2186,127 +2169,78 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::Never | ty::Ref(_, _, hir::Mutability::Not) | ty::Array(..) => { - // Implementations provided in libcore - None + unreachable!("tried to assemble `Sized` for type with libcore-provided impl") } // FIXME(unsafe_binder): Should we conditionally // (i.e. universally) implement copy/clone? - ty::UnsafeBinder(_) => None, - - ty::Dynamic(..) - | ty::Str - | ty::Slice(..) - | ty::Foreign(..) - | ty::Ref(_, _, hir::Mutability::Mut) => None, + ty::UnsafeBinder(_) => unreachable!("tried to assemble `Sized` for unsafe binder"), ty::Tuple(tys) => { // (*) binder moved here - Where(obligation.predicate.rebind(tys.iter().collect())) + ty::Binder::dummy(tys.iter().collect()) } ty::Pat(ty, _) => { // (*) binder moved here - Where(obligation.predicate.rebind(vec![ty])) + ty::Binder::dummy(vec![ty]) } ty::Coroutine(coroutine_def_id, args) => { match self.tcx().coroutine_movability(coroutine_def_id) { - hir::Movability::Static => None, + hir::Movability::Static => { + unreachable!("tried to assemble `Sized` for static coroutine") + } hir::Movability::Movable => { if self.tcx().features().coroutine_clone() { - let resolved_upvars = - self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); - let resolved_witness = - self.infcx.shallow_resolve(args.as_coroutine().witness()); - if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() { - // Not yet resolved. - Ambiguous - } else { - let all = args - .as_coroutine() + ty::Binder::dummy( + args.as_coroutine() .upvar_tys() .iter() .chain([args.as_coroutine().witness()]) - .collect::<Vec<_>>(); - Where(obligation.predicate.rebind(all)) - } + .collect::<Vec<_>>(), + ) } else { - None + unreachable!( + "tried to assemble `Sized` for coroutine without enabled feature" + ) } } } } - ty::CoroutineWitness(def_id, args) => { - let hidden_types = rebind_coroutine_witness_types( - self.infcx.tcx, - def_id, - args, - obligation.predicate.bound_vars(), - ); - Where(hidden_types) - } + ty::CoroutineWitness(def_id, args) => self + .infcx + .tcx + .coroutine_hidden_types(def_id) + .instantiate(self.infcx.tcx, args) + .map_bound(|witness| witness.types.to_vec()), - ty::Closure(_, args) => { - // (*) binder moved here - let ty = self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty()); - if let ty::Infer(ty::TyVar(_)) = ty.kind() { - // Not yet resolved. - Ambiguous - } else { - Where(obligation.predicate.rebind(args.as_closure().upvar_tys().to_vec())) - } - } + ty::Closure(_, args) => ty::Binder::dummy(args.as_closure().upvar_tys().to_vec()), ty::CoroutineClosure(_, args) => { - // (*) binder moved here - let ty = self.infcx.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty()); - if let ty::Infer(ty::TyVar(_)) = ty.kind() { - // Not yet resolved. - Ambiguous - } else { - Where( - obligation - .predicate - .rebind(args.as_coroutine_closure().upvar_tys().to_vec()), - ) - } + ty::Binder::dummy(args.as_coroutine_closure().upvar_tys().to_vec()) } - ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => { - // Fallback to whatever user-defined impls exist in this case. - None - } - - ty::Infer(ty::TyVar(_)) => { - // Unbound type variable. Might or might not have - // applicable impls and so forth, depending on what - // those type variables wind up being bound to. - Ambiguous - } - - // We can make this an ICE if/once we actually instantiate the trait obligation eagerly. - ty::Bound(..) => None, - - ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + ty::Foreign(..) + | ty::Str + | ty::Slice(_) + | ty::Dynamic(..) + | ty::Adt(..) + | ty::Alias(..) + | ty::Param(..) + | ty::Placeholder(..) + | ty::Bound(..) + | ty::Ref(_, _, ty::Mutability::Mut) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); } } } - fn fused_iterator_conditions( - &mut self, - obligation: &PolyTraitObligation<'tcx>, - ) -> BuiltinImplConditions<'tcx> { - let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); - if let ty::Coroutine(did, ..) = *self_ty.kind() - && self.tcx().coroutine_is_gen(did) - { - BuiltinImplConditions::Where(ty::Binder::dummy(Vec::new())) - } else { - BuiltinImplConditions::None - } + fn coroutine_is_gen(&mut self, self_ty: Ty<'tcx>) -> bool { + matches!(*self_ty.kind(), ty::Coroutine(did, ..) + if self.tcx().coroutine_is_gen(did)) } /// For default impls, we need to break apart a type into its @@ -2323,9 +2257,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { #[instrument(level = "debug", skip(self), ret)] fn constituent_types_for_ty( &self, - t: ty::Binder<'tcx, Ty<'tcx>>, + t: Ty<'tcx>, ) -> Result<ty::Binder<'tcx, Vec<Ty<'tcx>>>, SelectionError<'tcx>> { - Ok(match *t.skip_binder().kind() { + Ok(match *t.kind() { ty::Uint(_) | ty::Int(_) | ty::Bool @@ -2342,8 +2276,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // `assemble_candidates_from_auto_impls`. ty::Foreign(..) => ty::Binder::dummy(Vec::new()), - // FIXME(unsafe_binders): Squash the double binder for now, I guess. - ty::UnsafeBinder(_) => return Err(SelectionError::Unimplemented), + ty::UnsafeBinder(ty) => ty.map_bound(|ty| vec![ty]), // Treat this like `struct str([u8]);` ty::Str => ty::Binder::dummy(vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)]), @@ -2357,40 +2290,47 @@ impl<'tcx> SelectionContext<'_, 'tcx> { bug!("asked to assemble constituent types of unexpected type: {:?}", t); } - ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => t.rebind(vec![element_ty]), + ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => { + ty::Binder::dummy(vec![element_ty]) + } - ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => t.rebind(vec![ty]), + ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => ty::Binder::dummy(vec![ty]), ty::Tuple(tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - t.rebind(tys.iter().collect()) + ty::Binder::dummy(tys.iter().collect()) } ty::Closure(_, args) => { let ty = self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty()); - t.rebind(vec![ty]) + ty::Binder::dummy(vec![ty]) } ty::CoroutineClosure(_, args) => { let ty = self.infcx.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty()); - t.rebind(vec![ty]) + ty::Binder::dummy(vec![ty]) } ty::Coroutine(_, args) => { let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); let witness = args.as_coroutine().witness(); - t.rebind([ty].into_iter().chain(iter::once(witness)).collect()) + ty::Binder::dummy([ty].into_iter().chain(iter::once(witness)).collect()) } - ty::CoroutineWitness(def_id, args) => { - rebind_coroutine_witness_types(self.infcx.tcx, def_id, args, t.bound_vars()) - } + ty::CoroutineWitness(def_id, args) => self + .infcx + .tcx + .coroutine_hidden_types(def_id) + .instantiate(self.infcx.tcx, args) + .map_bound(|witness| witness.types.to_vec()), // For `PhantomData<T>`, we pass `T`. - ty::Adt(def, args) if def.is_phantom_data() => t.rebind(args.types().collect()), + ty::Adt(def, args) if def.is_phantom_data() => { + ty::Binder::dummy(args.types().collect()) + } ty::Adt(def, args) => { - t.rebind(def.all_fields().map(|f| f.ty(self.tcx(), args)).collect()) + ty::Binder::dummy(def.all_fields().map(|f| f.ty(self.tcx(), args)).collect()) } ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { @@ -2401,7 +2341,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // which enforces a DAG between the functions requiring // the auto trait bounds in question. match self.tcx().type_of_opaque(def_id) { - Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]), + Ok(ty) => ty::Binder::dummy(vec![ty.instantiate(self.tcx(), args)]), Err(_) => { return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id)); } @@ -2873,23 +2813,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } -fn rebind_coroutine_witness_types<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, - args: ty::GenericArgsRef<'tcx>, - bound_vars: &'tcx ty::List<ty::BoundVariableKind>, -) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> { - let bound_coroutine_types = tcx.coroutine_hidden_types(def_id).skip_binder(); - 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.types.to_vec()).instantiate(tcx, args), - tcx.mk_bound_variable_kinds_from_iter( - bound_vars.iter().chain(bound_coroutine_types.bound_vars()), - ), - ) -} - impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> { TraitObligationStackList::with(self) diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index b30fadd3e5b..4bb12694c47 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -233,7 +233,7 @@ pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool /// /// For the purposes of const traits, we also check that the specializing /// impl is not more restrictive than the parent impl. That is, if the -/// `parent_impl_def_id` is a const impl (conditionally based off of some `~const` +/// `parent_impl_def_id` is a const impl (conditionally based off of some `[const]` /// bounds), then `specializing_impl_def_id` must also be const for the same /// set of types. #[instrument(skip(tcx), level = "debug")] diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index 9452dca9a4f..19eb85506b6 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -273,8 +273,6 @@ impl<'tcx> Graph { // Descend the specialization tree, where `parent` is the current parent node. loop { - use self::Inserted::*; - let insert_result = self.children.entry(parent).or_default().insert( tcx, impl_def_id, @@ -283,11 +281,11 @@ impl<'tcx> Graph { )?; match insert_result { - BecameNewSibling(opt_lint) => { + Inserted::BecameNewSibling(opt_lint) => { last_lint = opt_lint; break; } - ReplaceChildren(grand_children_to_be) => { + Inserted::ReplaceChildren(grand_children_to_be) => { // We currently have // // P @@ -326,7 +324,7 @@ impl<'tcx> Graph { } break; } - ShouldRecurseOn(new_parent) => { + Inserted::ShouldRecurseOn(new_parent) => { parent = new_parent; } } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index a05bae53566..0c14b124e25 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -80,6 +80,7 @@ pub fn expand_trait_aliases<'tcx>( | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => {} } } @@ -368,16 +369,24 @@ pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc // Proving `Sized`/`MetaSized`, very often on "obviously sized" types like // `&T`, accounts for about 60% percentage of the predicates we have to prove. No need to // canonicalize and all that for such cases. - if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = predicate.kind().skip_binder() + && trait_pred.polarity == ty::PredicatePolarity::Positive { - let sizedness = match tcx.as_lang_item(trait_ref.def_id()) { + let sizedness = match tcx.as_lang_item(trait_pred.def_id()) { Some(LangItem::Sized) => SizedTraitKind::Sized, Some(LangItem::MetaSized) => SizedTraitKind::MetaSized, _ => return false, }; - if trait_ref.self_ty().has_trivial_sizedness(tcx, sizedness) { + // FIXME(sized_hierarchy): this temporarily reverts the `sized_hierarchy` feature + // while a proper fix for `tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs` + // is pending a proper fix + if !tcx.features().sized_hierarchy() && matches!(sizedness, SizedTraitKind::MetaSized) { + return true; + } + + if trait_pred.self_ty().has_trivial_sizedness(tcx, sizedness) { debug!("fast path -- trivial sizedness"); return true; } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index d4e6a23f0eb..adce9850b59 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -197,6 +197,7 @@ pub fn clause_obligations<'tcx>( ty::ClauseKind::ConstEvaluatable(ct) => { wf.add_wf_preds_for_term(ct.into()); } + ty::ClauseKind::UnstableFeature(_) => {} } wf.normalize(infcx) @@ -288,9 +289,9 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( && let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.def_id) && let Some(impl_item) = - items.iter().find(|item| item.id.owner_id.to_def_id() == impl_item_id) + items.iter().find(|item| item.owner_id.to_def_id() == impl_item_id) { - Some(tcx.hir_impl_item(impl_item.id).expect_type().span) + Some(tcx.hir_impl_item(*impl_item).expect_type().span) } else { None } @@ -1095,6 +1096,7 @@ pub fn object_region_bounds<'tcx>( | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::ConstEvaluatable(_) => None, } }) |
