diff options
Diffstat (limited to 'compiler/rustc_infer')
48 files changed, 908 insertions, 768 deletions
diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 64f52ea7ac1..fbe8d31370c 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -104,10 +104,10 @@ infer_compare_impl_item_obligation = ...so that the definition in impl matches t infer_consider_specifying_length = consider specifying the actual array length infer_data_flows = ...but data{$label_var1_exists -> [true] {" "}from `{$label_var1}` - *[false] -> {""} + *[false] {""} } flows{$label_var2_exists -> [true] {" "}into `{$label_var2}` - *[false] -> {""} + *[false] {""} } here infer_data_lifetime_flow = ...but data with one lifetime flows into the other here @@ -164,7 +164,10 @@ infer_label_bad = {$bad_kind -> infer_lf_bound_not_satisfied = lifetime bound not satisfied infer_lifetime_mismatch = lifetime mismatch -infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl -> +infer_lifetime_param_suggestion = consider {$is_reuse -> + [true] reusing + *[false] introducing +} a named lifetime parameter{$is_impl -> [true] {" "}and update trait if needed *[false] {""} } diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 4593108edac..a801001eaf9 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1,9 +1,12 @@ use hir::GenericParamKind; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ codes::*, Applicability, Diag, DiagMessage, DiagStyledString, EmissionGuarantee, IntoDiagArg, MultiSpan, SubdiagMessageOp, Subdiagnostic, }; use rustc_hir as hir; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::FnRetTy; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath; @@ -239,7 +242,7 @@ impl Subdiagnostic for RegionOriginNote<'_> { fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { let mut label_or_note = |span, msg: DiagMessage| { let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count(); @@ -304,7 +307,7 @@ impl Subdiagnostic for LifetimeMismatchLabels { fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { match self { LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { @@ -342,6 +345,7 @@ impl Subdiagnostic for LifetimeMismatchLabels { pub struct AddLifetimeParamsSuggestion<'a> { pub tcx: TyCtxt<'a>, + pub generic_param_scope: LocalDefId, pub sub: Region<'a>, pub ty_sup: &'a hir::Ty<'a>, pub ty_sub: &'a hir::Ty<'a>, @@ -352,34 +356,37 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { let mut mk_suggestion = || { - let ( - hir::Ty { kind: hir::TyKind::Ref(lifetime_sub, _), .. }, - hir::Ty { kind: hir::TyKind::Ref(lifetime_sup, _), .. }, - ) = (self.ty_sub, self.ty_sup) + let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub) else { return false; }; - if !lifetime_sub.is_anonymous() || !lifetime_sup.is_anonymous() { - return false; - }; - - let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else { - return false; - }; - let node = self.tcx.hir_node_by_def_id(anon_reg.def_id); let is_impl = matches!(&node, hir::Node::ImplItem(_)); - let generics = match node { + let (generics, parent_generics) = match node { hir::Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, ref generics, ..), .. }) | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. }) - | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics, + | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => ( + generics, + match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.def_id)) + { + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Trait(_, _, ref generics, ..), + .. + }) + | hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }), + .. + }) => Some(generics), + _ => None, + }, + ), _ => return false, }; @@ -390,24 +397,112 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { .map(|p| p.name.ident().name) .find(|i| *i != kw::UnderscoreLifetime); let introduce_new = suggestion_param_name.is_none(); + + let mut default = "'a".to_string(); + if let Some(parent_generics) = parent_generics { + let used: FxHashSet<_> = parent_generics + .params + .iter() + .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) + .map(|p| p.name.ident().name) + .filter(|i| *i != kw::UnderscoreLifetime) + .map(|l| l.to_string()) + .collect(); + if let Some(lt) = + ('a'..='z').map(|it| format!("'{it}")).find(|it| !used.contains(it)) + { + // We want a lifetime that *isn't* present in the `trait` or `impl` that assoc + // `fn` belongs to. We could suggest reusing one of their lifetimes, but it is + // likely to be an over-constraining lifetime requirement, so we always add a + // lifetime to the `fn`. + default = lt; + } + } let suggestion_param_name = - suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned()); - - debug!(?lifetime_sup.ident.span); - debug!(?lifetime_sub.ident.span); - let make_suggestion = |ident: Ident| { - let sugg = if ident.name == kw::Empty { - format!("{suggestion_param_name}, ") - } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() { - format!("{suggestion_param_name} ") - } else { - suggestion_param_name.clone() - }; - (ident.span, sugg) - }; - let mut suggestions = - vec![make_suggestion(lifetime_sub.ident), make_suggestion(lifetime_sup.ident)]; + suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| default); + + struct ImplicitLifetimeFinder { + suggestions: Vec<(Span, String)>, + suggestion_param_name: String, + } + impl<'v> Visitor<'v> for ImplicitLifetimeFinder { + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { + let make_suggestion = |ident: Ident| { + if ident.name == kw::Empty && ident.span.is_empty() { + format!("{}, ", self.suggestion_param_name) + } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() { + format!("{} ", self.suggestion_param_name) + } else { + self.suggestion_param_name.clone() + } + }; + match ty.kind { + hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { + for segment in path.segments { + if let Some(args) = segment.args { + if args.args.iter().all(|arg| { + matches!( + arg, + hir::GenericArg::Lifetime(lifetime) + if lifetime.ident.name == kw::Empty + ) + }) { + self.suggestions.push(( + segment.ident.span.shrink_to_hi(), + format!( + "<{}>", + args.args + .iter() + .map(|_| self.suggestion_param_name.clone()) + .collect::<Vec<_>>() + .join(", ") + ), + )); + } else { + for arg in args.args { + if let hir::GenericArg::Lifetime(lifetime) = arg + && lifetime.is_anonymous() + { + self.suggestions.push(( + lifetime.ident.span, + make_suggestion(lifetime.ident), + )); + } + } + } + } + } + } + hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => { + self.suggestions + .push((lifetime.ident.span, make_suggestion(lifetime.ident))); + } + _ => {} + } + walk_ty(self, ty); + } + } + let mut visitor = ImplicitLifetimeFinder { + suggestions: vec![], + suggestion_param_name: suggestion_param_name.clone(), + }; + if let Some(fn_decl) = node.fn_decl() + && let hir::FnRetTy::Return(ty) = fn_decl.output + { + visitor.visit_ty(ty); + } + if visitor.suggestions.is_empty() { + // 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. + visitor.visit_ty(self.ty_sup); + } + visitor.visit_ty(self.ty_sub); + if visitor.suggestions.is_empty() { + return false; + } if introduce_new { let new_param_suggestion = if let Some(first) = generics.params.iter().find(|p| !p.name.ident().span.is_empty()) @@ -417,15 +512,16 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { (generics.span, format!("<{suggestion_param_name}>")) }; - suggestions.push(new_param_suggestion); + visitor.suggestions.push(new_param_suggestion); } - - diag.multipart_suggestion( + diag.multipart_suggestion_verbose( fluent::infer_lifetime_param_suggestion, - suggestions, + visitor.suggestions, Applicability::MaybeIncorrect, ); diag.arg("is_impl", is_impl); + diag.arg("is_reuse", !introduce_new); + true }; if mk_suggestion() && self.add_note { @@ -454,7 +550,7 @@ impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( mut self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { self.unmet_requirements .push_span_label(self.binding_span, fluent::infer_msl_introduces_static); @@ -773,7 +869,7 @@ impl Subdiagnostic for ConsiderBorrowingParamHelp { fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( self, diag: &mut Diag<'_, G>, - f: F, + f: &F, ) { let mut type_param_span: MultiSpan = self.spans.clone().into(); for &span in &self.spans { @@ -818,7 +914,7 @@ impl Subdiagnostic for DynTraitConstraintSuggestion { fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( self, diag: &mut Diag<'_, G>, - f: F, + f: &F, ) { let mut multi_span: MultiSpan = vec![self.span].into(); multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label); @@ -865,7 +961,7 @@ impl Subdiagnostic for ReqIntroducedLocations { fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( mut self, diag: &mut Diag<'_, G>, - f: F, + f: &F, ) { for sp in self.spans { self.span.push_span_label(sp, fluent::infer_ril_introduced_here); @@ -888,7 +984,7 @@ impl Subdiagnostic for MoreTargeted { fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { diag.code(E0772); diag.primary_message(fluent::infer_more_targeted); @@ -1293,7 +1389,7 @@ impl Subdiagnostic for SuggestTuplePatternMany { fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( self, diag: &mut Diag<'_, G>, - f: F, + f: &F, ) { diag.arg("path", self.path); let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into()); diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 7b962b01408..4fbeb0ec102 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -1,6 +1,8 @@ use crate::fluent_generated as fluent; use crate::infer::error_reporting::nice_region_error::find_anon_type; use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, SubdiagMessageOp, Subdiagnostic}; +use rustc_hir::def_id::LocalDefId; +use rustc_middle::bug; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{symbol::kw, Span}; @@ -13,12 +15,15 @@ struct DescriptionCtx<'a> { impl<'a> DescriptionCtx<'a> { fn new<'tcx>( tcx: TyCtxt<'tcx>, + generic_param_scope: LocalDefId, region: ty::Region<'tcx>, alt_span: Option<Span>, ) -> Option<Self> { let (span, kind, arg) = match *region { - ty::ReEarlyParam(ref br) => { - let scope = region.free_region_binding_scope(tcx).expect_local(); + ty::ReEarlyParam(br) => { + let scope = tcx + .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id) + .expect_local(); let span = if let Some(param) = tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) { @@ -34,11 +39,12 @@ impl<'a> DescriptionCtx<'a> { } ty::ReLateParam(ref fr) => { if !fr.bound_region.is_named() - && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) + && let Some((ty, _)) = + find_anon_type(tcx, generic_param_scope, region, &fr.bound_region) { (Some(ty.span), "defined_here", String::new()) } else { - let scope = region.free_region_binding_scope(tcx).expect_local(); + let scope = fr.scope.expect_local(); match fr.bound_region { ty::BoundRegionKind::BrNamed(_, name) => { let span = if let Some(param) = tcx @@ -69,16 +75,8 @@ impl<'a> DescriptionCtx<'a> { ty::RePlaceholder(_) | ty::ReError(_) => return None, - // FIXME(#13998) RePlaceholder should probably print like - // ReLateParam rather than dumping Debug output on the user. - // - // We shouldn't really be having unification failures with ReVar - // and ReBound though. - // - // FIXME(@lcnr): figure out why we have to handle `ReBound` - // here, this feels somewhat off. ty::ReVar(_) | ty::ReBound(..) | ty::ReErased => { - (alt_span, "revar", format!("{region:?}")) + bug!("unexpected region for DescriptionCtx: {:?}", region); } }; Some(DescriptionCtx { span, kind, arg }) @@ -150,12 +148,17 @@ pub struct RegionExplanation<'a> { impl RegionExplanation<'_> { pub fn new<'tcx>( tcx: TyCtxt<'tcx>, + generic_param_scope: LocalDefId, region: ty::Region<'tcx>, alt_span: Option<Span>, prefix: PrefixKind, suffix: SuffixKind, ) -> Option<Self> { - Some(Self { desc: DescriptionCtx::new(tcx, region, alt_span)?, prefix, suffix }) + Some(Self { + desc: DescriptionCtx::new(tcx, generic_param_scope, region, alt_span)?, + prefix, + suffix, + }) } } @@ -163,7 +166,7 @@ impl Subdiagnostic for RegionExplanation<'_> { fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( self, diag: &mut Diag<'_, G>, - f: F, + f: &F, ) { diag.arg("pref_kind", self.prefix); diag.arg("suff_kind", self.suffix); diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 0f21d3966c4..17e6d6250ad 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -27,6 +27,7 @@ use super::*; +use rustc_middle::bug; use rustc_middle::ty::relate::{Relate, TypeRelation}; use rustc_middle::ty::{Const, ImplSubject}; @@ -47,11 +48,6 @@ pub struct At<'a, 'tcx> { pub param_env: ty::ParamEnv<'tcx>, } -pub struct Trace<'a, 'tcx> { - at: At<'a, 'tcx>, - trace: TypeTrace<'tcx>, -} - impl<'tcx> InferCtxt<'tcx> { #[inline] pub fn at<'a>( @@ -108,9 +104,6 @@ impl<'a, 'tcx> At<'a, 'tcx> { /// call like `foo(x)`, where `foo: fn(i32)`, you might have /// `sup(i32, x)`, since the "expected" type is the type that /// appears in the signature. - /// - /// See [`At::trace`] and [`Trace::sub`] for a version of - /// this method that only requires `T: Relate<'tcx>` pub fn sup<T>( self, define_opaque_types: DefineOpaqueTypes, @@ -120,13 +113,19 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - self.trace(expected, actual).sup(define_opaque_types, expected, actual) + let mut fields = CombineFields::new( + self.infcx, + ToTrace::to_trace(self.cause, true, expected, actual), + self.param_env, + define_opaque_types, + ); + fields + .sup() + .relate(expected, actual) + .map(|_| InferOk { value: (), obligations: fields.obligations }) } /// Makes `expected <: actual`. - /// - /// See [`At::trace`] and [`Trace::sub`] for a version of - /// this method that only requires `T: Relate<'tcx>` pub fn sub<T>( self, define_opaque_types: DefineOpaqueTypes, @@ -136,13 +135,19 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - self.trace(expected, actual).sub(define_opaque_types, expected, actual) + let mut fields = CombineFields::new( + self.infcx, + ToTrace::to_trace(self.cause, true, expected, actual), + self.param_env, + define_opaque_types, + ); + fields + .sub() + .relate(expected, actual) + .map(|_| InferOk { value: (), obligations: fields.obligations }) } - /// Makes `expected <: actual`. - /// - /// See [`At::trace`] and [`Trace::eq`] for a version of - /// this method that only requires `T: Relate<'tcx>` + /// Makes `expected == actual`. pub fn eq<T>( self, define_opaque_types: DefineOpaqueTypes, @@ -152,7 +157,40 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - self.trace(expected, actual).eq(define_opaque_types, expected, actual) + let mut fields = CombineFields::new( + self.infcx, + ToTrace::to_trace(self.cause, true, expected, actual), + self.param_env, + define_opaque_types, + ); + fields + .equate(StructurallyRelateAliases::No) + .relate(expected, actual) + .map(|_| InferOk { value: (), obligations: fields.obligations }) + } + + /// Equates `expected` and `found` while structurally relating aliases. + /// This should only be used inside of the next generation trait solver + /// when relating rigid aliases. + pub fn eq_structurally_relating_aliases<T>( + self, + expected: T, + actual: T, + ) -> InferResult<'tcx, ()> + where + T: ToTrace<'tcx>, + { + assert!(self.infcx.next_trait_solver()); + let mut fields = CombineFields::new( + self.infcx, + ToTrace::to_trace(self.cause, true, expected, actual), + self.param_env, + DefineOpaqueTypes::Yes, + ); + fields + .equate(StructurallyRelateAliases::Yes) + .relate(expected, actual) + .map(|_| InferOk { value: (), obligations: fields.obligations }) } pub fn relate<T>( @@ -184,9 +222,6 @@ impl<'a, 'tcx> At<'a, 'tcx> { /// this can result in an error (e.g., if asked to compute LUB of /// u32 and i32), it is meaningful to call one of them the /// "expected type". - /// - /// See [`At::trace`] and [`Trace::lub`] for a version of - /// this method that only requires `T: Relate<'tcx>` pub fn lub<T>( self, define_opaque_types: DefineOpaqueTypes, @@ -196,15 +231,21 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - self.trace(expected, actual).lub(define_opaque_types, expected, actual) + let mut fields = CombineFields::new( + self.infcx, + ToTrace::to_trace(self.cause, true, expected, actual), + self.param_env, + define_opaque_types, + ); + fields + .lub() + .relate(expected, actual) + .map(|value| InferOk { value, obligations: fields.obligations }) } /// Computes the greatest-lower-bound, or mutual subtype, of two /// values. As with `lub` order doesn't matter, except for error /// cases. - /// - /// See [`At::trace`] and [`Trace::glb`] for a version of - /// this method that only requires `T: Relate<'tcx>` pub fn glb<T>( self, define_opaque_types: DefineOpaqueTypes, @@ -214,105 +255,16 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - self.trace(expected, actual).glb(define_opaque_types, expected, actual) - } - - /// Sets the "trace" values that will be used for - /// error-reporting, but doesn't actually perform any operation - /// yet (this is useful when you want to set the trace using - /// distinct values from those you wish to operate upon). - pub fn trace<T>(self, expected: T, actual: T) -> Trace<'a, 'tcx> - where - T: ToTrace<'tcx>, - { - let trace = ToTrace::to_trace(self.cause, true, expected, actual); - Trace { at: self, trace } - } -} - -impl<'a, 'tcx> Trace<'a, 'tcx> { - /// Makes `a <: b`. - #[instrument(skip(self), level = "debug")] - pub fn sub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()> - where - T: Relate<'tcx>, - { - let Trace { at, trace } = self; - let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); - fields - .sub() - .relate(a, b) - .map(move |_| InferOk { value: (), obligations: fields.obligations }) - } - - /// Makes `a :> b`. - #[instrument(skip(self), level = "debug")] - pub fn sup<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()> - where - T: Relate<'tcx>, - { - let Trace { at, trace } = self; - let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); - fields - .sup() - .relate(a, b) - .map(move |_| InferOk { value: (), obligations: fields.obligations }) - } - - /// Makes `a == b`. - #[instrument(skip(self), level = "debug")] - pub fn eq<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()> - where - T: Relate<'tcx>, - { - let Trace { at, trace } = self; - let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); - fields - .equate(StructurallyRelateAliases::No) - .relate(a, b) - .map(move |_| InferOk { value: (), obligations: fields.obligations }) - } - - /// Equates `a` and `b` while structurally relating aliases. This should only - /// be used inside of the next generation trait solver when relating rigid aliases. - #[instrument(skip(self), level = "debug")] - pub fn eq_structurally_relating_aliases<T>(self, a: T, b: T) -> InferResult<'tcx, ()> - where - T: Relate<'tcx>, - { - let Trace { at, trace } = self; - debug_assert!(at.infcx.next_trait_solver()); - let mut fields = at.infcx.combine_fields(trace, at.param_env, DefineOpaqueTypes::Yes); - fields - .equate(StructurallyRelateAliases::Yes) - .relate(a, b) - .map(move |_| InferOk { value: (), obligations: fields.obligations }) - } - - #[instrument(skip(self), level = "debug")] - pub fn lub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T> - where - T: Relate<'tcx>, - { - let Trace { at, trace } = self; - let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); - fields - .lub() - .relate(a, b) - .map(move |t| InferOk { value: t, obligations: fields.obligations }) - } - - #[instrument(skip(self), level = "debug")] - pub fn glb<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T> - where - T: Relate<'tcx>, - { - let Trace { at, trace } = self; - let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); + let mut fields = CombineFields::new( + self.infcx, + ToTrace::to_trace(self.cause, true, expected, actual), + self.param_env, + define_opaque_types, + ); fields .glb() - .relate(a, b) - .map(move |t| InferOk { value: t, obligations: fields.obligations }) + .relate(expected, actual) + .map(|value| InferOk { value, obligations: fields.obligations }) } } @@ -384,19 +336,31 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> { a: Self, b: Self, ) -> TypeTrace<'tcx> { - use GenericArgKind::*; TypeTrace { cause: cause.clone(), values: match (a.unpack(), b.unpack()) { - (Lifetime(a), Lifetime(b)) => Regions(ExpectedFound::new(a_is_expected, a, b)), - (Type(a), Type(b)) => Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), - (Const(a), Const(b)) => { + (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => { + Regions(ExpectedFound::new(a_is_expected, a, b)) + } + (GenericArgKind::Type(a), GenericArgKind::Type(b)) => { + Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) + } + (GenericArgKind::Const(a), GenericArgKind::Const(b)) => { Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) } - (Lifetime(_), Type(_) | Const(_)) - | (Type(_), Lifetime(_) | Const(_)) - | (Const(_), Lifetime(_) | Type(_)) => { + ( + GenericArgKind::Lifetime(_), + GenericArgKind::Type(_) | GenericArgKind::Const(_), + ) + | ( + GenericArgKind::Type(_), + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_), + ) + | ( + GenericArgKind::Const(_), + GenericArgKind::Lifetime(_) | GenericArgKind::Type(_), + ) => { bug!("relating different kinds: {a:?} {b:?}") } }, @@ -436,6 +400,20 @@ impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> { a: Self, b: Self, ) -> TypeTrace<'tcx> { + TypeTrace { + cause: cause.clone(), + values: Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())), + } + } +} + +impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> { + fn to_trace( + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self, + ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), values: Aliases(ExpectedFound::new(a_is_expected, a, b)) } } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 4d712e9ffd3..27b06c4b73e 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -9,6 +9,7 @@ use crate::infer::canonical::{ Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues, }; use crate::infer::InferCtxt; +use rustc_middle::bug; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::GenericArg; use rustc_middle::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt}; diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index c8adbf7f57a..de0e15ef3de 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -7,6 +7,8 @@ //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html use crate::infer::canonical::{Canonical, CanonicalVarValues}; +use rustc_macros::extension; +use rustc_middle::bug; use rustc_middle::ty::fold::{FnMutDelegate, TypeFoldable}; use rustc_middle::ty::GenericArgKind; use rustc_middle::ty::{self, TyCtxt}; diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 734fa919eb5..1abb8086d41 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -21,8 +21,7 @@ //! //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html -use crate::infer::ConstVariableOrigin; -use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin}; +use crate::infer::{InferCtxt, RegionVariableOrigin}; use rustc_index::IndexVec; use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::ty::fold::TypeFoldable; @@ -114,10 +113,9 @@ impl<'tcx> InferCtxt<'tcx> { match cv_info.kind { CanonicalVarKind::Ty(ty_kind) => { let ty = match ty_kind { - CanonicalTyVarKind::General(ui) => self.next_ty_var_in_universe( - TypeVariableOrigin { param_def_id: None, span }, - universe_map(ui), - ), + CanonicalTyVarKind::General(ui) => { + self.next_ty_var_in_universe(span, universe_map(ui)) + } CanonicalTyVarKind::Int => self.next_int_var(), @@ -145,13 +143,9 @@ impl<'tcx> InferCtxt<'tcx> { ty::Region::new_placeholder(self.tcx, placeholder_mapped).into() } - CanonicalVarKind::Const(ui, ty) => self - .next_const_var_in_universe( - ty, - ConstVariableOrigin { param_def_id: None, span }, - universe_map(ui), - ) - .into(), + CanonicalVarKind::Const(ui, ty) => { + self.next_const_var_in_universe(ty, span, universe_map(ui)).into() + } CanonicalVarKind::Effect => { let vid = self .inner diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index b948067e750..1732913e191 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -25,6 +25,7 @@ use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, BoundVar, Ty, TyCtxt}; use rustc_middle::ty::{GenericArg, GenericArgKind}; +use rustc_middle::{bug, span_bug}; use std::fmt::Debug; use std::iter; diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 29c9f08a166..95fbc1e66ce 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -61,17 +61,19 @@ use crate::traits::{ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diag, DiagCtxt, DiagStyledString, - ErrorGuaranteed, IntoDiagArg, + ErrorGuaranteed, IntoDiagArg, StringPart, }; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; +use rustc_macros::extension; +use rustc_middle::bug; use rustc_middle::dep_graph::DepContext; -use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError}; +use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError, PrintTraitRefExt as _}; use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; -use rustc_middle::ty::ToPredicate; +use rustc_middle::ty::Upcast; use rustc_middle::ty::{ self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -159,6 +161,7 @@ impl<'tcx> Deref for TypeErrCtxt<'_, 'tcx> { pub(super) fn note_and_explain_region<'tcx>( tcx: TyCtxt<'tcx>, err: &mut Diag<'_>, + generic_param_scope: LocalDefId, prefix: &str, region: ty::Region<'tcx>, suffix: &str, @@ -166,16 +169,17 @@ pub(super) fn note_and_explain_region<'tcx>( ) { let (description, span) = match *region { ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::RePlaceholder(_) | ty::ReStatic => { - msg_span_from_named_region(tcx, region, alt_span) + msg_span_from_named_region(tcx, generic_param_scope, region, alt_span) } ty::ReError(_) => return, - // We shouldn't really be having unification failures with ReVar - // and ReBound though. - // - // FIXME(@lcnr): Figure out whether this is reachable and if so, why. - ty::ReVar(_) | ty::ReBound(..) | ty::ReErased => (format!("lifetime `{region}`"), alt_span), + // FIXME(#125431): `ReVar` shouldn't reach here. + ty::ReVar(_) => (format!("lifetime `{region}`"), alt_span), + + ty::ReBound(..) | ty::ReErased => { + bug!("unexpected region for note_and_explain_region: {:?}", region); + } }; emit_msg_span(err, prefix, description, span, suffix); @@ -184,23 +188,27 @@ pub(super) fn note_and_explain_region<'tcx>( fn explain_free_region<'tcx>( tcx: TyCtxt<'tcx>, err: &mut Diag<'_>, + generic_param_scope: LocalDefId, prefix: &str, region: ty::Region<'tcx>, suffix: &str, ) { - let (description, span) = msg_span_from_named_region(tcx, region, None); + let (description, span) = msg_span_from_named_region(tcx, generic_param_scope, region, None); label_msg_span(err, prefix, description, span, suffix); } fn msg_span_from_named_region<'tcx>( tcx: TyCtxt<'tcx>, + generic_param_scope: LocalDefId, region: ty::Region<'tcx>, alt_span: Option<Span>, ) -> (String, Option<Span>) { match *region { - ty::ReEarlyParam(ref br) => { - let scope = region.free_region_binding_scope(tcx).expect_local(); + ty::ReEarlyParam(br) => { + let scope = tcx + .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id) + .expect_local(); let span = if let Some(param) = tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) { @@ -217,21 +225,21 @@ fn msg_span_from_named_region<'tcx>( } ty::ReLateParam(ref fr) => { if !fr.bound_region.is_named() - && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) + && let Some((ty, _)) = + find_anon_type(tcx, generic_param_scope, region, &fr.bound_region) { ("the anonymous lifetime defined here".to_string(), Some(ty.span)) } else { - let scope = region.free_region_binding_scope(tcx).expect_local(); match fr.bound_region { ty::BoundRegionKind::BrNamed(_, name) => { let span = if let Some(param) = tcx .hir() - .get_generics(scope) + .get_generics(generic_param_scope) .and_then(|generics| generics.get_named(name)) { param.span } else { - tcx.def_span(scope) + tcx.def_span(generic_param_scope) }; let text = if name == kw::UnderscoreLifetime { "the anonymous lifetime as defined here".to_string() @@ -242,11 +250,11 @@ fn msg_span_from_named_region<'tcx>( } ty::BrAnon => ( "the anonymous lifetime as defined here".to_string(), - Some(tcx.def_span(scope)), + Some(tcx.def_span(generic_param_scope)), ), _ => ( format!("the lifetime `{region}` as defined here"), - Some(tcx.def_span(scope)), + Some(tcx.def_span(generic_param_scope)), ), } } @@ -299,6 +307,7 @@ fn label_msg_span( #[instrument(level = "trace", skip(tcx))] pub fn unexpected_hidden_region_diagnostic<'tcx>( tcx: TyCtxt<'tcx>, + generic_param_scope: LocalDefId, span: Span, hidden_ty: Ty<'tcx>, hidden_region: ty::Region<'tcx>, @@ -324,11 +333,12 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( explain_free_region( tcx, &mut err, + generic_param_scope, &format!("hidden type `{hidden_ty}` captures "), hidden_region, "", ); - if let Some(reg_info) = tcx.is_suitable_region(hidden_region) { + if let Some(reg_info) = tcx.is_suitable_region(generic_param_scope, hidden_region) { let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id); nice_region_error::suggest_new_region_bound( tcx, @@ -346,6 +356,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( explain_free_region( tcx, &mut err, + generic_param_scope, &format!("hidden type `{}` captures ", hidden_ty), hidden_region, "", @@ -373,6 +384,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( note_and_explain_region( tcx, &mut err, + generic_param_scope, &format!("hidden type `{hidden_ty}` captures "), hidden_region, "", @@ -411,7 +423,7 @@ impl<'tcx> InferCtxt<'tcx> { .kind() .map_bound(|kind| match kind { ty::ClauseKind::Projection(projection_predicate) - if projection_predicate.projection_ty.def_id == item_def_id => + if projection_predicate.projection_term.def_id == item_def_id => { projection_predicate.term.ty() } @@ -447,7 +459,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { for error in errors { debug!("report_region_errors: error = {:?}", error); - guar = Some(if let Some(guar) = self.try_report_nice_region_error(&error) { + let e = if let Some(guar) = + self.try_report_nice_region_error(generic_param_scope, &error) + { guar } else { match error.clone() { @@ -460,9 +474,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // general bit of code that displays the error information RegionResolutionError::ConcreteFailure(origin, sub, sup) => { if sub.is_placeholder() || sup.is_placeholder() { - self.report_placeholder_failure(origin, sub, sup).emit() + self.report_placeholder_failure(generic_param_scope, origin, sub, sup) + .emit() } else { - self.report_concrete_failure(origin, sub, sup).emit() + self.report_concrete_failure(generic_param_scope, origin, sub, sup) + .emit() } } @@ -485,12 +501,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { _, ) => { if sub_r.is_placeholder() { - self.report_placeholder_failure(sub_origin, sub_r, sup_r).emit() + self.report_placeholder_failure( + generic_param_scope, + sub_origin, + sub_r, + sup_r, + ) + .emit() } else if sup_r.is_placeholder() { - self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit() + self.report_placeholder_failure( + generic_param_scope, + sup_origin, + sub_r, + sup_r, + ) + .emit() } else { self.report_sub_sup_conflict( - var_origin, sub_origin, sub_r, sup_origin, sup_r, + generic_param_scope, + var_origin, + sub_origin, + sub_r, + sup_origin, + sup_r, ) } } @@ -511,19 +544,27 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // value. let sub_r = self.tcx.lifetimes.re_erased; - self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit() + self.report_placeholder_failure( + generic_param_scope, + sup_origin, + sub_r, + sup_r, + ) + .emit() } RegionResolutionError::CannotNormalize(clause, origin) => { let clause: ty::Clause<'tcx> = - clause.map_bound(ty::ClauseKind::TypeOutlives).to_predicate(self.tcx); + clause.map_bound(ty::ClauseKind::TypeOutlives).upcast(self.tcx); self.tcx .dcx() .struct_span_err(origin.span(), format!("cannot normalize `{clause}`")) .emit() } } - }) + }; + + guar = Some(e) } guar.unwrap() @@ -884,9 +925,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { err.help("...or use `match` instead of `let...else`"); } _ => { - if let ObligationCauseCode::BindingObligation(_, span) - | ObligationCauseCode::ExprBindingObligation(_, span, ..) = + if let ObligationCauseCode::WhereClause(_, span) + | ObligationCauseCode::WhereClauseInExpr(_, span, ..) = cause.code().peel_derives() + && !span.is_dummy() && let TypeError::RegionsPlaceholderMismatch = terr { err.span_note(*span, "the lifetime requirement is introduced here"); @@ -1052,8 +1094,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // unsafe extern "C" for<'a> fn(&'a T) -> &'a T // ^^^^^^ - values.0.push(sig1.unsafety.prefix_str(), sig1.unsafety != sig2.unsafety); - values.1.push(sig2.unsafety.prefix_str(), sig1.unsafety != sig2.unsafety); + values.0.push(sig1.safety.prefix_str(), sig1.safety != sig2.safety); + values.1.push(sig2.safety.prefix_str(), sig1.safety != sig2.safety); // unsafe extern "C" for<'a> fn(&'a T) -> &'a T // ^^^^^^^^^^ @@ -1917,6 +1959,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); if !is_simple_error || terr.must_include_note() { diag.note_expected_found(&expected_label, expected, &found_label, found); + + if let Some(ty::Closure(_, args)) = + exp_found.map(|expected_type_found| expected_type_found.found.kind()) + { + diag.highlighted_note(vec![ + StringPart::normal("closure has signature: `"), + StringPart::highlighted( + self.tcx + .signature_unclosure( + args.as_closure().sig(), + rustc_hir::Safety::Safe, + ) + .to_string(), + ), + StringPart::normal("`"), + ]); + } } } } @@ -1996,7 +2055,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { trace: &TypeTrace<'tcx>, terr: TypeError<'tcx>, ) -> Vec<TypeErrorAdditionalDiags> { - use crate::traits::ObligationCauseCode::{BlockTailExpression, MatchExpressionArm}; let mut suggestions = Vec::new(); let span = trace.cause.span(); let values = self.resolve_vars_if_possible(trace.values); @@ -2044,10 +2102,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // If a string was expected and the found expression is a character literal, // perhaps the user meant to write `"s"` to specify a string literal. (ty::Ref(_, r, _), ty::Char) if r.is_str() => { - suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral { - start: span.with_hi(span.lo() + BytePos(1)), - end: span.with_lo(span.hi() - BytePos(1)), - }) + if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) + && code.starts_with("'") + && code.ends_with("'") + { + suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral { + start: span.with_hi(span.lo() + BytePos(1)), + end: span.with_lo(span.hi() - BytePos(1)), + }); + } } // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`, // we try to suggest to add the missing `let` for `if let Some(..) = expr` @@ -2063,8 +2126,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } let code = trace.cause.code(); - if let &(MatchExpressionArm(box MatchExpressionArmCause { source, .. }) - | BlockTailExpression(.., source)) = code + if let &(ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { + source, + .. + }) + | ObligationCauseCode::BlockTailExpression(.., source)) = code && let hir::MatchSource::TryDesugar(_) = source && let Some((expected_ty, found_ty, _)) = self.values_str(trace.values) { @@ -2324,7 +2390,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { '_explain: { let (description, span) = match sub.kind() { ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => { - msg_span_from_named_region(self.tcx, sub, Some(span)) + msg_span_from_named_region(self.tcx, generic_param_scope, sub, Some(span)) } _ => (format!("lifetime `{sub}`"), Some(span)), }; @@ -2352,9 +2418,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { generic_param_scope = self.tcx.local_parent(generic_param_scope); } - // type_param_sugg_span is (span, has_bounds) + // type_param_sugg_span is (span, has_bounds, needs_parentheses) let (type_scope, type_param_sugg_span) = match bound_kind { - GenericKind::Param(ref param) => { + GenericKind::Param(param) => { let generics = self.tcx.generics_of(generic_param_scope); let def_id = generics.type_param(param, self.tcx).def_id.expect_local(); let scope = self.tcx.local_def_id_to_hir_id(def_id).owner.def_id; @@ -2363,10 +2429,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // instead we suggest `T: 'a + 'b` in that case. let hir_generics = self.tcx.hir().get_generics(scope).unwrap(); let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) { - Some(span) => Some((span, true)), + Some((span, open_paren_sp)) => Some((span, true, open_paren_sp)), // If `param` corresponds to `Self`, no usable suggestion span. None if generics.has_self && param.index == 0 => None, - None => Some((self.tcx.def_span(def_id).shrink_to_hi(), false)), + None => Some((self.tcx.def_span(def_id).shrink_to_hi(), false, None)), }; (scope, sugg_span) } @@ -2375,7 +2441,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let suggestion_scope = { let lifetime_scope = match sub.kind() { ty::ReStatic => hir::def_id::CRATE_DEF_ID, - _ => match self.tcx.is_suitable_region(sub) { + _ => match self.tcx.is_suitable_region(generic_param_scope, sub) { Some(info) => info.def_id, None => generic_param_scope, }, @@ -2387,14 +2453,20 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; let mut suggs = vec![]; - let lt_name = self.suggest_name_region(sub, &mut suggs); + let lt_name = self.suggest_name_region(generic_param_scope, sub, &mut suggs); - if let Some((sp, has_lifetimes)) = type_param_sugg_span + if let Some((sp, has_lifetimes, open_paren_sp)) = type_param_sugg_span && suggestion_scope == type_scope { let suggestion = if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") }; - suggs.push((sp, suggestion)) + + if let Some(open_paren_sp) = open_paren_sp { + suggs.push((open_paren_sp, "(".to_string())); + suggs.push((sp, format!("){suggestion}"))); + } else { + suggs.push((sp, suggestion)) + } } else if let GenericKind::Alias(ref p) = bound_kind && let ty::Projection = p.kind(self.tcx) && let DefKind::AssocTy = self.tcx.def_kind(p.def_id) @@ -2426,6 +2498,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub fn suggest_name_region( &self, + generic_param_scope: LocalDefId, lifetime: Region<'tcx>, add_lt_suggs: &mut Vec<(Span, String)>, ) -> String { @@ -2472,18 +2545,19 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - let (lifetime_def_id, lifetime_scope) = match self.tcx.is_suitable_region(lifetime) { - Some(info) if !lifetime.has_name() => { - (info.bound_region.get_id().unwrap().expect_local(), info.def_id) - } - _ => 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.has_name() => { + (info.bound_region.get_id().unwrap().expect_local(), info.def_id) + } + _ => return lifetime.get_name_or_anon().to_string(), + }; let new_lt = { let generics = self.tcx.generics_of(lifetime_scope); let mut used_names = iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p))) - .flat_map(|g| &g.params) + .flat_map(|g| &g.own_params) .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime)) .map(|p| p.name) .collect::<Vec<_>>(); @@ -2528,6 +2602,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn report_sub_sup_conflict( &self, + generic_param_scope: LocalDefId, var_origin: RegionVariableOrigin, sub_origin: SubregionOrigin<'tcx>, sub_region: Region<'tcx>, @@ -2539,6 +2614,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { note_and_explain_region( self.tcx, &mut err, + generic_param_scope, "first, the lifetime cannot outlive ", sup_region, "...", @@ -2561,6 +2637,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { note_and_explain_region( self.tcx, &mut err, + generic_param_scope, "...but the lifetime must also be valid for ", sub_region, "...", @@ -2584,6 +2661,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { note_and_explain_region( self.tcx, &mut err, + generic_param_scope, "but, the lifetime must be valid for ", sub_region, "...", @@ -2751,19 +2829,17 @@ pub enum FailureCode { #[extension(pub trait ObligationCauseExt<'tcx>)] impl<'tcx> ObligationCause<'tcx> { fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode { - use self::FailureCode::*; - use crate::traits::ObligationCauseCode::*; match self.code() { - IfExpressionWithNoElse => Error0317, - MainFunctionType => Error0580, - CompareImplItemObligation { .. } - | MatchExpressionArm(_) - | IfExpression { .. } - | LetElse - | StartFunctionType - | LangFunctionType(_) - | IntrinsicType - | MethodReceiver => Error0308, + ObligationCauseCode::IfExpressionWithNoElse => FailureCode::Error0317, + ObligationCauseCode::MainFunctionType => FailureCode::Error0580, + ObligationCauseCode::CompareImplItem { .. } + | ObligationCauseCode::MatchExpressionArm(_) + | ObligationCauseCode::IfExpression { .. } + | ObligationCauseCode::LetElse + | ObligationCauseCode::StartFunctionType + | ObligationCauseCode::LangFunctionType(_) + | ObligationCauseCode::IntrinsicType + | ObligationCauseCode::MethodReceiver => FailureCode::Error0308, // In the case where we have no more specific thing to // say, also take a look at the error code, maybe we can @@ -2772,10 +2848,10 @@ impl<'tcx> ObligationCause<'tcx> { TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() => { - Error0644 + FailureCode::Error0644 } - TypeError::IntrinsicCast => Error0308, - _ => Error0308, + TypeError::IntrinsicCast => FailureCode::Error0308, + _ => FailureCode::Error0308, }, } } @@ -2785,36 +2861,51 @@ impl<'tcx> ObligationCause<'tcx> { span: Span, subdiags: Vec<TypeErrorAdditionalDiags>, ) -> ObligationCauseFailureCode { - use crate::traits::ObligationCauseCode::*; match self.code() { - CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => { ObligationCauseFailureCode::MethodCompat { span, subdiags } } - CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => { ObligationCauseFailureCode::TypeCompat { span, subdiags } } - CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { ObligationCauseFailureCode::ConstCompat { span, subdiags } } - BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => { + ObligationCauseCode::BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => { ObligationCauseFailureCode::TryCompat { span, subdiags } } - MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source { + ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { + source, .. + }) => match source { hir::MatchSource::TryDesugar(_) => { ObligationCauseFailureCode::TryCompat { span, subdiags } } _ => ObligationCauseFailureCode::MatchCompat { span, subdiags }, }, - IfExpression { .. } => ObligationCauseFailureCode::IfElseDifferent { span, subdiags }, - IfExpressionWithNoElse => ObligationCauseFailureCode::NoElse { span }, - LetElse => ObligationCauseFailureCode::NoDiverge { span, subdiags }, - MainFunctionType => ObligationCauseFailureCode::FnMainCorrectType { span }, - StartFunctionType => ObligationCauseFailureCode::FnStartCorrectType { span, subdiags }, - &LangFunctionType(lang_item_name) => { + ObligationCauseCode::IfExpression { .. } => { + ObligationCauseFailureCode::IfElseDifferent { span, subdiags } + } + ObligationCauseCode::IfExpressionWithNoElse => { + ObligationCauseFailureCode::NoElse { span } + } + ObligationCauseCode::LetElse => { + ObligationCauseFailureCode::NoDiverge { span, subdiags } + } + ObligationCauseCode::MainFunctionType => { + ObligationCauseFailureCode::FnMainCorrectType { span } + } + ObligationCauseCode::StartFunctionType => { + ObligationCauseFailureCode::FnStartCorrectType { span, subdiags } + } + &ObligationCauseCode::LangFunctionType(lang_item_name) => { ObligationCauseFailureCode::FnLangCorrectType { span, subdiags, lang_item_name } } - IntrinsicType => ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags }, - MethodReceiver => ObligationCauseFailureCode::MethodCorrectType { span, subdiags }, + ObligationCauseCode::IntrinsicType => { + ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags } + } + ObligationCauseCode::MethodReceiver => { + ObligationCauseFailureCode::MethodCorrectType { span, subdiags } + } // In the case where we have no more specific thing to // say, also take a look at the error code, maybe we can @@ -2834,22 +2925,21 @@ impl<'tcx> ObligationCause<'tcx> { } fn as_requirement_str(&self) -> &'static str { - use crate::traits::ObligationCauseCode::*; match self.code() { - CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => { "method type is compatible with trait" } - CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => { "associated type is compatible with trait" } - CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { "const is compatible with trait" } - MainFunctionType => "`main` function has the correct type", - StartFunctionType => "`#[start]` function has the correct type", - LangFunctionType(_) => "lang item function has the correct type", - IntrinsicType => "intrinsic has the correct type", - MethodReceiver => "method receiver has the correct type", + ObligationCauseCode::MainFunctionType => "`main` function has the correct type", + ObligationCauseCode::StartFunctionType => "`#[start]` function has the correct type", + ObligationCauseCode::LangFunctionType(_) => "lang item function has the correct type", + ObligationCauseCode::IntrinsicType => "intrinsic has the correct type", + ObligationCauseCode::MethodReceiver => "method receiver has the correct type", _ => "types are compatible", } } @@ -2860,16 +2950,17 @@ pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>); impl IntoDiagArg for ObligationCauseAsDiagArg<'_> { fn into_diag_arg(self) -> rustc_errors::DiagArgValue { - use crate::traits::ObligationCauseCode::*; let kind = match self.0.code() { - CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => "method_compat", - CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => "type_compat", - CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => "const_compat", - MainFunctionType => "fn_main_correct_type", - StartFunctionType => "fn_start_correct_type", - LangFunctionType(_) => "fn_lang_correct_type", - IntrinsicType => "intrinsic_correct_type", - MethodReceiver => "method_correct_type", + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => "method_compat", + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => "type_compat", + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { + "const_compat" + } + ObligationCauseCode::MainFunctionType => "fn_main_correct_type", + ObligationCauseCode::StartFunctionType => "fn_start_correct_type", + ObligationCauseCode::LangFunctionType(_) => "fn_lang_correct_type", + ObligationCauseCode::IntrinsicType => "intrinsic_correct_type", + ObligationCauseCode::MethodReceiver => "method_correct_type", _ => "other", } .into(); diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index a2a38d1c507..98fd7906e70 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -3,7 +3,6 @@ use crate::errors::{ SourceKindMultiSuggestion, SourceKindSubdiag, }; use crate::infer::error_reporting::TypeErrCtxt; -use crate::infer::type_variable::TypeVariableOrigin; use crate::infer::InferCtxt; use rustc_errors::{codes::*, Diag, IntoDiagArg}; use rustc_hir as hir; @@ -12,8 +11,9 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource}; +use rustc_middle::bug; use rustc_middle::hir::nested_filter; -use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue}; +use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; use rustc_middle::ty::{ @@ -168,7 +168,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ClosureEraser<'tcx> { let closure_sig = args.as_closure().sig(); Ty::new_fn_ptr( self.tcx, - self.tcx.signature_unclosure(closure_sig, hir::Unsafety::Normal), + self.tcx.signature_unclosure(closure_sig, hir::Safety::Safe), ) } _ => ty.super_fold_with(self), @@ -522,7 +522,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer_subdiags.push(SourceKindSubdiag::GenericLabel { span, is_type, - param_name: generics.params[argument_index].name.to_string(), + param_name: generics.own_params[argument_index].name.to_string(), parent_exists, parent_prefix, parent_name, @@ -542,18 +542,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match arg.unpack() { GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), - GenericArgKind::Type(_) => self - .next_ty_var(TypeVariableOrigin { - span: DUMMY_SP, - param_def_id: None, - }) - .into(), - GenericArgKind::Const(arg) => self - .next_const_var( - arg.ty(), - ConstVariableOrigin { span: DUMMY_SP, param_def_id: None }, - ) - .into(), + GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(), + GenericArgKind::Const(arg) => { + self.next_const_var(arg.ty(), DUMMY_SP).into() + } } })) .unwrap(); @@ -569,9 +561,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } InferSourceKind::FullyQualifiedMethodCall { receiver, successor, args, def_id } => { - let placeholder = Some( - self.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, param_def_id: None }), - ); + let placeholder = Some(self.next_ty_var(DUMMY_SP)); if let Some(args) = args.make_suggestable(self.infcx.tcx, true, placeholder) { let mut printer = fmt_printer(self, Namespace::ValueNS); printer.print_def_path(def_id, args).unwrap(); @@ -605,9 +595,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => { - let placeholder = Some( - self.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, param_def_id: None }), - ); + let placeholder = Some(self.next_ty_var(DUMMY_SP)); if let Some(ty) = ty.make_suggestable(self.infcx.tcx, true, placeholder) { let ty_info = ty_to_string(self, ty, None); multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return( diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index 84bfa5b5af7..cbeec591960 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -13,6 +13,7 @@ use crate::infer::TyCtxt; use rustc_errors::Subdiagnostic; use rustc_errors::{Diag, ErrorGuaranteed}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::Ty; use rustc_middle::ty::Region; @@ -66,17 +67,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } // Determine whether the sub and sup consist of both anonymous (elided) regions. - let anon_reg_sup = self.tcx().is_suitable_region(sup)?; + let anon_reg_sup = self.tcx().is_suitable_region(self.generic_param_scope, sup)?; - let anon_reg_sub = self.tcx().is_suitable_region(sub)?; + let anon_reg_sub = self.tcx().is_suitable_region(self.generic_param_scope, sub)?; let scope_def_id_sup = anon_reg_sup.def_id; let bregion_sup = anon_reg_sup.bound_region; let scope_def_id_sub = anon_reg_sub.def_id; let bregion_sub = anon_reg_sub.bound_region; - let ty_sup = find_anon_type(self.tcx(), sup, &bregion_sup)?; + let ty_sup = find_anon_type(self.tcx(), self.generic_param_scope, sup, &bregion_sup)?; - let ty_sub = find_anon_type(self.tcx(), sub, &bregion_sub)?; + let ty_sub = find_anon_type(self.tcx(), self.generic_param_scope, sub, &bregion_sub)?; debug!( "try_report_anon_anon_conflict: found_param1={:?} sup={:?} br1={:?}", @@ -127,8 +128,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { }, }; - let suggestion = - AddLifetimeParamsSuggestion { tcx: self.tcx(), sub, ty_sup, ty_sub, add_note: true }; + let suggestion = AddLifetimeParamsSuggestion { + tcx: self.tcx(), + sub, + ty_sup, + ty_sub, + add_note: true, + generic_param_scope: self.generic_param_scope, + }; let err = LifetimeMismatch { span, labels, suggestion }; let reported = self.tcx().dcx().emit_err(err); Some(reported) @@ -139,11 +146,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// removed in favour of public_errors::AddLifetimeParamsSuggestion pub fn suggest_adding_lifetime_params<'tcx>( tcx: TyCtxt<'tcx>, + err: &mut Diag<'_>, + generic_param_scope: LocalDefId, sub: Region<'tcx>, ty_sup: &'tcx Ty<'_>, ty_sub: &'tcx Ty<'_>, - err: &mut Diag<'_>, ) { - let suggestion = AddLifetimeParamsSuggestion { tcx, sub, ty_sup, ty_sub, add_note: false }; + let suggestion = AddLifetimeParamsSuggestion { + tcx, + sub, + ty_sup, + ty_sub, + add_note: false, + generic_param_scope, + }; suggestion.add_to_diag(err); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index 265a315a559..b91b755d683 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -1,5 +1,6 @@ use core::ops::ControlFlow; use rustc_hir as hir; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; @@ -23,10 +24,11 @@ use rustc_middle::ty::{self, Region, TyCtxt}; /// for e.g., `&u8` and `Vec<&u8>`. pub fn find_anon_type<'tcx>( tcx: TyCtxt<'tcx>, + generic_param_scope: LocalDefId, region: Region<'tcx>, br: &ty::BoundRegionKind, ) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnSig<'tcx>)> { - let anon_reg = tcx.is_suitable_region(region)?; + let anon_reg = tcx.is_suitable_region(generic_param_scope, region)?; let fn_sig = tcx.hir_node_by_def_id(anon_reg.def_id).fn_sig()?; fn_sig diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs index b93b8dc03f8..7996b4bf65b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs @@ -13,6 +13,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; +use rustc_middle::bug; use rustc_middle::ty::TypeVisitor; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { @@ -32,17 +33,20 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // If we added a "points at argument expression" obligation, we remove it here, we care // about the original obligation only. let code = match cause.code() { - ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => &*parent_code, + ObligationCauseCode::FunctionArg { parent_code, .. } => &*parent_code, code => code, }; let ObligationCauseCode::MatchImpl(parent, impl_def_id) = code else { return None; }; - let (ObligationCauseCode::BindingObligation(_, binding_span) - | ObligationCauseCode::ExprBindingObligation(_, binding_span, ..)) = *parent.code() + let (ObligationCauseCode::WhereClause(_, binding_span) + | ObligationCauseCode::WhereClauseInExpr(_, binding_span, ..)) = *parent.code() else { return None; }; + if binding_span.is_dummy() { + return None; + } // FIXME: we should point at the lifetime let multi_span: MultiSpan = vec![binding_span].into(); @@ -53,6 +57,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let expl = note_and_explain::RegionExplanation::new( self.tcx(), + self.generic_param_scope, sup, Some(binding_span), note_and_explain::PrefixKind::Empty, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs index 62c163f0b7f..cffdfa88752 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs @@ -2,6 +2,7 @@ use crate::infer::error_reporting::TypeErrCtxt; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::lexical_region_resolve::RegionResolutionError::*; use rustc_errors::{Diag, ErrorGuaranteed}; +use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Span; @@ -23,30 +24,39 @@ pub use util::find_param_with_region; impl<'cx, 'tcx> TypeErrCtxt<'cx, 'tcx> { pub fn try_report_nice_region_error( &'cx self, + generic_param_scope: LocalDefId, error: &RegionResolutionError<'tcx>, ) -> Option<ErrorGuaranteed> { - NiceRegionError::new(self, error.clone()).try_report() + NiceRegionError::new(self, generic_param_scope, error.clone()).try_report() } } pub struct NiceRegionError<'cx, 'tcx> { cx: &'cx TypeErrCtxt<'cx, 'tcx>, + /// The innermost definition that introduces generic parameters that may be involved in + /// the region errors we are dealing with. + generic_param_scope: LocalDefId, error: Option<RegionResolutionError<'tcx>>, regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>, } impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { - pub fn new(cx: &'cx TypeErrCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self { - Self { cx, error: Some(error), regions: None } + pub fn new( + cx: &'cx TypeErrCtxt<'cx, 'tcx>, + generic_param_scope: LocalDefId, + error: RegionResolutionError<'tcx>, + ) -> Self { + Self { cx, error: Some(error), regions: None, generic_param_scope } } pub fn new_from_span( cx: &'cx TypeErrCtxt<'cx, 'tcx>, + generic_param_scope: LocalDefId, span: Span, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>, ) -> Self { - Self { cx, error: None, regions: Some((span, sub, sup)) } + Self { cx, error: None, regions: Some((span, sub, sup)), generic_param_scope } } fn tcx(&self) -> TyCtxt<'tcx> { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 239c2db30e2..29da12e7d15 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -27,12 +27,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // 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 Some(region_info) = self.tcx().is_suitable_region(sup) + && 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() - && let Some(region_info) = self.tcx().is_suitable_region(sub) + && 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) { (sup, sub, anon_param_info, region_info) @@ -72,7 +72,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { return None; } - if find_anon_type(self.tcx(), anon, &br).is_some() + if find_anon_type(self.tcx(), self.generic_param_scope, anon, &br).is_some() && self.is_self_anon(is_first, scope_def_id) { return None; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index 01e75d59f4d..e125f1858dd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -10,9 +10,10 @@ use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::intern::Interned; use rustc_errors::{Diag, IntoDiagArg}; use rustc_hir::def::Namespace; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; +use rustc_middle::bug; use rustc_middle::ty::error::ExpectedFound; -use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode}; +use rustc_middle::ty::print::{FmtPrinter, Print, PrintTraitRefExt as _, RegionHighlightMode}; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, RePlaceholder, Region, TyCtxt}; @@ -240,8 +241,9 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { let span = cause.span(); let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) = - if let ObligationCauseCode::ItemObligation(def_id) - | ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code() + if let ObligationCauseCode::WhereClause(def_id, span) + | ObligationCauseCode::WhereClauseInExpr(def_id, span, ..) = *cause.code() + && def_id != CRATE_DEF_ID.to_def_id() { ( true, @@ -407,10 +409,8 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { { let closure_sig = self_ty.map(|closure| { if let ty::Closure(_, args) = closure.kind() { - self.tcx().signature_unclosure( - args.as_closure().sig(), - rustc_hir::Unsafety::Normal, - ) + self.tcx() + .signature_unclosure(args.as_closure().sig(), rustc_hir::Safety::Safe) } else { bug!("type is not longer closure"); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 0bbabefaf95..71a86683c21 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -49,7 +49,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { if let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code() { // This may have a closure and it would cause ICE // through `find_param_with_region` (#78262). - let anon_reg_sup = tcx.is_suitable_region(*sup_r)?; + let anon_reg_sup = tcx.is_suitable_region(self.generic_param_scope, *sup_r)?; let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); if fn_returns.is_empty() { return None; @@ -92,7 +92,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})", var_origin, sub_origin, sub_r, sup_origin, sup_r ); - let anon_reg_sup = tcx.is_suitable_region(*sup_r)?; + let anon_reg_sup = tcx.is_suitable_region(self.generic_param_scope, *sup_r)?; debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup); let sp = var_origin.span(); let return_sp = sub_origin.span(); @@ -214,8 +214,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { _ => cause.code(), } && let ( - &ObligationCauseCode::ItemObligation(item_def_id) - | &ObligationCauseCode::ExprItemObligation(item_def_id, ..), + &ObligationCauseCode::WhereClause(item_def_id, _) + | &ObligationCauseCode::WhereClauseInExpr(item_def_id, ..), None, ) = (code, override_error_code) { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index b4cf727bf8f..7f3e23716f9 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -4,13 +4,13 @@ use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff} use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{Subtype, ValuePairs}; -use crate::traits::ObligationCauseCode::CompareImplItemObligation; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; +use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::print::RegionHighlightMode; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; @@ -31,7 +31,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { _, ) = error.clone() && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin) - && let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code() + && let ObligationCauseCode::CompareImplItem { trait_item_def_id, .. } = + sub_trace.cause.code() && sub_trace.values == sup_trace.values && let ValuePairs::PolySigs(ExpectedFound { expected, found }) = sub_trace.values { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index f1f8314661f..5f3f1081ca8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -37,13 +37,15 @@ pub struct AnonymousParamInfo<'tcx> { #[instrument(skip(tcx), level = "debug")] pub fn find_param_with_region<'tcx>( tcx: TyCtxt<'tcx>, + generic_param_scope: LocalDefId, anon_region: Region<'tcx>, replace_region: Region<'tcx>, ) -> Option<AnonymousParamInfo<'tcx>> { let (id, bound_region) = match *anon_region { ty::ReLateParam(late_param) => (late_param.scope, late_param.bound_region), ty::ReEarlyParam(ebr) => { - (tcx.parent(ebr.def_id), ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name)) + let region_def = tcx.generics_of(generic_param_scope).region_param(ebr, tcx).def_id; + (tcx.parent(region_def), ty::BoundRegionKind::BrNamed(region_def, ebr.name)) } _ => return None, // not a free region }; @@ -53,7 +55,7 @@ pub fn find_param_with_region<'tcx>( // FIXME: use def_kind // Don't perform this on closures - match tcx.hir_node_by_def_id(def_id) { + match tcx.hir_node_by_def_id(generic_param_scope) { hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => { return None; } @@ -110,7 +112,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { anon_region: Region<'tcx>, replace_region: Region<'tcx>, ) -> Option<AnonymousParamInfo<'tcx>> { - find_param_with_region(self.tcx(), anon_region, replace_region) + find_param_with_region(self.tcx(), self.generic_param_scope, anon_region, replace_region) } // Here, we check for the case where the anonymous region diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 3ae1165d2a4..acb74f8a82c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -75,6 +75,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub(super) fn report_concrete_failure( &self, + generic_param_scope: LocalDefId, origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, @@ -89,6 +90,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { note_and_explain_region( self.tcx, &mut err, + generic_param_scope, "", sup, " doesn't meet the lifetime requirements", @@ -99,6 +101,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { note_and_explain_region( self.tcx, &mut err, + generic_param_scope, "the required lifetime does not necessarily outlive ", sub, "", @@ -106,10 +109,19 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); } _ => { - note_and_explain_region(self.tcx, &mut err, "", sup, "...", None); note_and_explain_region( self.tcx, &mut err, + generic_param_scope, + "", + sup, + "...", + None, + ); + note_and_explain_region( + self.tcx, + &mut err, + generic_param_scope, "...does not necessarily outlive ", sub, "", @@ -122,6 +134,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::Reborrow(span) => { let reference_valid = note_and_explain::RegionExplanation::new( self.tcx, + generic_param_scope, sub, None, note_and_explain::PrefixKind::RefValidFor, @@ -129,6 +142,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); let content_valid = note_and_explain::RegionExplanation::new( self.tcx, + generic_param_scope, sup, None, note_and_explain::PrefixKind::ContentValidFor, @@ -142,6 +156,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::RelateObjectBound(span) => { let object_valid = note_and_explain::RegionExplanation::new( self.tcx, + generic_param_scope, sub, None, note_and_explain::PrefixKind::TypeObjValidFor, @@ -149,6 +164,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); let pointer_valid = note_and_explain::RegionExplanation::new( self.tcx, + generic_param_scope, sup, None, note_and_explain::PrefixKind::SourcePointerValidFor, @@ -170,7 +186,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { note_and_explain::SuffixKind::Empty }; let note = note_and_explain::RegionExplanation::new( - self.tcx, sub, opt_span, prefix, suffix, + self.tcx, + generic_param_scope, + sub, + opt_span, + prefix, + suffix, ); self.dcx().create_err(FulfillReqLifetime { span, @@ -181,6 +202,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::RelateRegionParamBound(span) => { let param_instantiated = note_and_explain::RegionExplanation::new( self.tcx, + generic_param_scope, sup, None, note_and_explain::PrefixKind::LfParamInstantiatedWith, @@ -188,6 +210,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); let param_must_outlive = note_and_explain::RegionExplanation::new( self.tcx, + generic_param_scope, sub, None, note_and_explain::PrefixKind::LfParamMustOutlive, @@ -201,6 +224,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::ReferenceOutlivesReferent(ty, span) => { let pointer_valid = note_and_explain::RegionExplanation::new( self.tcx, + generic_param_scope, sub, None, note_and_explain::PrefixKind::PointerValidFor, @@ -208,6 +232,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); let data_valid = note_and_explain::RegionExplanation::new( self.tcx, + generic_param_scope, sup, None, note_and_explain::PrefixKind::DataValidFor, @@ -239,7 +264,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { err } infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => { - let mut err = self.report_concrete_failure(*parent, sub, sup); + 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 // folks. @@ -262,6 +287,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::AscribeUserTypeProvePredicate(span) => { let instantiated = note_and_explain::RegionExplanation::new( self.tcx, + generic_param_scope, sup, None, note_and_explain::PrefixKind::LfInstantiatedWith, @@ -269,6 +295,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); let must_outlive = note_and_explain::RegionExplanation::new( self.tcx, + generic_param_scope, sub, None, note_and_explain::PrefixKind::LfMustOutlive, @@ -347,6 +374,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub(super) fn report_placeholder_failure( &self, + generic_param_scope: LocalDefId, placeholder_origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, @@ -357,21 +385,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::Subtype(box ref trace) if matches!( &trace.cause.code().peel_derives(), - ObligationCauseCode::BindingObligation(..) - | ObligationCauseCode::ExprBindingObligation(..) + ObligationCauseCode::WhereClause(..) + | ObligationCauseCode::WhereClauseInExpr(..) ) => { // Hack to get around the borrow checker because trace.cause has an `Rc`. - if let ObligationCauseCode::BindingObligation(_, span) - | ObligationCauseCode::ExprBindingObligation(_, span, ..) = + if let ObligationCauseCode::WhereClause(_, span) + | ObligationCauseCode::WhereClauseInExpr(_, span, ..) = &trace.cause.code().peel_derives() + && !span.is_dummy() { let span = *span; - self.report_concrete_failure(placeholder_origin, sub, sup) + self.report_concrete_failure(generic_param_scope, placeholder_origin, sub, sup) .with_span_note(span, "the lifetime requirement is introduced here") } else { unreachable!( - "control flow ensures we have a `BindingObligation` or `ExprBindingObligation` here..." + "control flow ensures we have a `BindingObligation` or `WhereClauseInExpr` here..." ) } } @@ -379,7 +408,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let terr = TypeError::RegionsPlaceholderMismatch; return self.report_and_explain_type_error(trace, terr); } - _ => return self.report_concrete_failure(placeholder_origin, sub, sup), + _ => { + return self.report_concrete_failure( + generic_param_scope, + placeholder_origin, + sub, + sup, + ); + } } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 008b75b4c9a..f4514c23508 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -28,7 +28,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match err { ArgumentSorts(values, _) | Sorts(values) => { - match (values.expected.kind(), values.found.kind()) { + match (*values.expected.kind(), *values.found.kind()) { (ty::Closure(..), ty::Closure(..)) => { diag.note("no two closures, even if identical, have the same type"); diag.help("consider boxing your closure and/or using it as a trait object"); @@ -54,17 +54,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } (ty::Param(expected), ty::Param(found)) => { let generics = tcx.generics_of(body_owner_def_id); - if let Some(param) = generics.opt_type_param(expected, tcx) { - let e_span = tcx.def_span(param.def_id); - if !sp.contains(e_span) { - diag.span_label(e_span, "expected type parameter"); - } + let e_span = tcx.def_span(generics.type_param(expected, tcx).def_id); + if !sp.contains(e_span) { + diag.span_label(e_span, "expected type parameter"); } - if let Some(param) = generics.opt_type_param(found, tcx) { - let f_span = tcx.def_span(param.def_id); - if !sp.contains(f_span) { - diag.span_label(f_span, "found type parameter"); - } + let f_span = tcx.def_span(generics.type_param(found, tcx).def_id); + if !sp.contains(f_span) { + diag.span_label(f_span, "found type parameter"); } diag.note( "a type parameter was expected, but a different one was found; \ @@ -87,29 +83,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { | (ty::Alias(ty::Projection, proj), ty::Param(p)) if !tcx.is_impl_trait_in_trait(proj.def_id) => { - let parent = tcx - .generics_of(body_owner_def_id) - .opt_type_param(p, tcx) - .and_then(|param| { - let p_def_id = param.def_id; - let p_span = tcx.def_span(p_def_id); - let expected = match (values.expected.kind(), values.found.kind()) { - (ty::Param(_), _) => "expected ", - (_, ty::Param(_)) => "found ", - _ => "", - }; - if !sp.contains(p_span) { - diag.span_label( - p_span, - format!("{expected}this type parameter"), - ); - } - p_def_id.as_local().and_then(|id| { - let local_id = tcx.local_def_id_to_hir_id(id); - let generics = tcx.parent_hir_node(local_id).generics()?; - Some((id, generics)) - }) - }); + let param = tcx.generics_of(body_owner_def_id).type_param(p, tcx); + let p_def_id = param.def_id; + let p_span = tcx.def_span(p_def_id); + let expected = match (values.expected.kind(), values.found.kind()) { + (ty::Param(_), _) => "expected ", + (_, ty::Param(_)) => "found ", + _ => "", + }; + if !sp.contains(p_span) { + diag.span_label(p_span, format!("{expected}this type parameter")); + } + let parent = p_def_id.as_local().and_then(|id| { + let local_id = tcx.local_def_id_to_hir_id(id); + let generics = tcx.parent_hir_node(local_id).generics()?; + Some((id, generics)) + }); let mut note = true; if let Some((local_id, generics)) = parent { // Synthesize the associated type restriction `Add<Output = Expected>`. @@ -183,16 +172,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..)) | (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => { let generics = tcx.generics_of(body_owner_def_id); - if let Some(param) = generics.opt_type_param(p, tcx) { - let p_span = tcx.def_span(param.def_id); - let expected = match (values.expected.kind(), values.found.kind()) { - (ty::Param(_), _) => "expected ", - (_, ty::Param(_)) => "found ", - _ => "", - }; - if !sp.contains(p_span) { - diag.span_label(p_span, format!("{expected}this type parameter")); - } + let p_span = tcx.def_span(generics.type_param(p, tcx).def_id); + let expected = match (values.expected.kind(), values.found.kind()) { + (ty::Param(_), _) => "expected ", + (_, ty::Param(_)) => "found ", + _ => "", + }; + if !sp.contains(p_span) { + diag.span_label(p_span, format!("{expected}this type parameter")); } diag.help("type parameters must be constrained to match other types"); if tcx.sess.teach(diag.code.unwrap()) { @@ -233,11 +220,9 @@ impl<T> Trait<T> for X { ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..), ) => { let generics = tcx.generics_of(body_owner_def_id); - if let Some(param) = generics.opt_type_param(p, tcx) { - let p_span = tcx.def_span(param.def_id); - if !sp.contains(p_span) { - diag.span_label(p_span, "expected this type parameter"); - } + let p_span = tcx.def_span(generics.type_param(p, tcx).def_id); + if !sp.contains(p_span) { + diag.span_label(p_span, "expected this type parameter"); } diag.help(format!( "every closure has a distinct type and so could not always match the \ @@ -246,16 +231,14 @@ impl<T> Trait<T> for X { } (ty::Param(p), _) | (_, ty::Param(p)) => { let generics = tcx.generics_of(body_owner_def_id); - if let Some(param) = generics.opt_type_param(p, tcx) { - let p_span = tcx.def_span(param.def_id); - let expected = match (values.expected.kind(), values.found.kind()) { - (ty::Param(_), _) => "expected ", - (_, ty::Param(_)) => "found ", - _ => "", - }; - if !sp.contains(p_span) { - diag.span_label(p_span, format!("{expected}this type parameter")); - } + let p_span = tcx.def_span(generics.type_param(p, tcx).def_id); + let expected = match (values.expected.kind(), values.found.kind()) { + (ty::Param(_), _) => "expected ", + (_, ty::Param(_)) => "found ", + _ => "", + }; + if !sp.contains(p_span) { + diag.span_label(p_span, format!("{expected}this type parameter")); } } (ty::Alias(ty::Projection | ty::Inherent, proj_ty), _) @@ -452,7 +435,7 @@ impl<T> Trait<T> for X { } (ty::FnPtr(sig), ty::FnDef(def_id, _)) | (ty::FnDef(def_id, _), ty::FnPtr(sig)) => { - if tcx.fn_sig(*def_id).skip_binder().unsafety() < sig.unsafety() { + if tcx.fn_sig(def_id).skip_binder().safety() < sig.safety() { diag.note( "unsafe functions cannot be coerced into safe function pointers", ); @@ -527,7 +510,7 @@ impl<T> Trait<T> for X { diag: &mut Diag<'_>, msg: impl Fn() -> String, body_owner_def_id: DefId, - proj_ty: &ty::AliasTy<'tcx>, + proj_ty: ty::AliasTy<'tcx>, ty: Ty<'tcx>, ) -> bool { let tcx = self.tcx; @@ -541,14 +524,12 @@ impl<T> Trait<T> for X { }; // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`. // This will also work for `impl Trait`. - let ty::Param(param_ty) = proj_ty.self_ty().kind() else { + let ty::Param(param_ty) = *proj_ty.self_ty().kind() else { return false; }; let generics = tcx.generics_of(body_owner_def_id); - let Some(param) = generics.opt_type_param(param_ty, tcx) else { - return false; - }; - let Some(def_id) = param.def_id.as_local() else { + let def_id = generics.type_param(param_ty, tcx).def_id; + let Some(def_id) = def_id.as_local() else { return false; }; @@ -598,7 +579,7 @@ impl<T> Trait<T> for X { fn expected_projection( &self, diag: &mut Diag<'_>, - proj_ty: &ty::AliasTy<'tcx>, + proj_ty: ty::AliasTy<'tcx>, values: ExpectedFound<Ty<'tcx>>, body_owner_def_id: DefId, cause_code: &ObligationCauseCode<'_>, @@ -629,8 +610,7 @@ impl<T> Trait<T> for X { | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }), ) ); - let impl_comparison = - matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. }); + let impl_comparison = matches!(cause_code, ObligationCauseCode::CompareImplItem { .. }); let assoc = tcx.associated_item(proj_ty.def_id); if impl_comparison { // We do not want to suggest calling functions when the reason of the @@ -709,7 +689,7 @@ fn foo(&self) -> Self::T { String::new() } &self, diag: &mut Diag<'_>, msg: impl Fn() -> String, - proj_ty: &ty::AliasTy<'tcx>, + proj_ty: ty::AliasTy<'tcx>, ty: Ty<'tcx>, ) -> bool { let tcx = self.tcx; diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index bf470bb1e3f..75479decebc 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -167,7 +167,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { exp_span, exp_found.expected, exp_found.found, ); - if let ObligationCauseCode::CompareImplItemObligation { .. } = cause.code() { + if let ObligationCauseCode::CompareImplItem { .. } = cause.code() { return; } diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index ef9c407acef..b2d89523ea8 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -32,6 +32,7 @@ //! inferencer knows "so far". use super::InferCtxt; use rustc_data_structures::fx::FxHashMap; +use rustc_middle::bug; use rustc_middle::infer::unify_key::ToType; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitableExt}; diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 5ae7f8bf504..72944c9c7de 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -20,6 +20,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ReBound, RePlaceholder, ReVar}; use rustc_middle::ty::{ReEarlyParam, ReErased, ReError, ReLateParam, ReStatic}; use rustc_middle::ty::{Region, RegionVid}; +use rustc_middle::{bug, span_bug}; use rustc_span::Span; use std::fmt; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 255e688fbc1..c8bb6cf5f9b 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -4,6 +4,7 @@ pub use lexical_region_resolve::RegionResolutionError; pub use relate::combine::CombineFields; pub use relate::combine::ObligationEmittingRelation; pub use relate::StructurallyRelateAliases; +pub use rustc_macros::{TypeFoldable, TypeVisitable}; pub use rustc_middle::ty::IntVarValue; pub use BoundRegionConversionTime::*; pub use RegionVariableOrigin::*; @@ -20,13 +21,13 @@ use opaque_types::OpaqueTypeStorage; use region_constraints::{GenericKind, VarInfos, VerifyBound}; use region_constraints::{RegionConstraintCollector, RegionConstraintStorage}; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::Rollback; use rustc_data_structures::unify as ut; use rustc_errors::{Diag, DiagCtxt, ErrorGuaranteed}; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_macros::extension; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::infer::unify_key::EffectVarValue; @@ -43,6 +44,7 @@ use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, GenericParamDefKind, InferConst, InferTy, Ty, TyCtxt}; use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid}; use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef}; +use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Symbol; use rustc_span::Span; use snapshot::undo_log::InferCtxtUndoLogs; @@ -367,33 +369,43 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { } } - fn root_ty_var(&self, vid: TyVid) -> TyVid { - self.root_var(vid) + fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { + self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) } - fn probe_ty_var(&self, vid: TyVid) -> Option<Ty<'tcx>> { - self.probe_ty_var(vid).ok() + fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> { + self.defining_opaque_types } - fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> Option<ty::Region<'tcx>> { - let re = self - .inner - .borrow_mut() - .unwrap_region_constraints() - .opportunistic_resolve_var(self.tcx, vid); - if *re == ty::ReVar(vid) { None } else { Some(re) } + fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> { + match self.probe_ty_var(vid) { + Ok(ty) => ty, + Err(_) => Ty::new_var(self.tcx, self.root_var(vid)), + } } - fn root_ct_var(&self, vid: ConstVid) -> ConstVid { - self.root_const_var(vid) + fn opportunistic_resolve_int_var(&self, vid: IntVid) -> Ty<'tcx> { + self.opportunistic_resolve_int_var(vid) } - fn probe_ct_var(&self, vid: ConstVid) -> Option<ty::Const<'tcx>> { - self.probe_const_var(vid).ok() + fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> Ty<'tcx> { + self.opportunistic_resolve_float_var(vid) } - fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> { - self.defining_opaque_types + fn opportunistic_resolve_ct_var(&self, vid: ConstVid, ty: Ty<'tcx>) -> ty::Const<'tcx> { + match self.probe_const_var(vid) { + Ok(ct) => ct, + Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid), ty), + } + } + + fn opportunistic_resolve_effect_var(&self, vid: EffectVid, ty: Ty<'tcx>) -> ty::Const<'tcx> { + match self.probe_effect_var(vid) { + Some(ct) => ct, + None => { + ty::Const::new_infer(self.tcx, InferConst::EffectVar(self.root_effect_var(vid)), ty) + } + } } } @@ -402,7 +414,7 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { pub enum ValuePairs<'tcx> { Regions(ExpectedFound<ty::Region<'tcx>>), Terms(ExpectedFound<ty::Term<'tcx>>), - Aliases(ExpectedFound<ty::AliasTy<'tcx>>), + Aliases(ExpectedFound<ty::AliasTerm<'tcx>>), TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>), PolySigs(ExpectedFound<ty::PolyFnSig<'tcx>>), ExistentialTraitRef(ExpectedFound<ty::PolyExistentialTraitRef<'tcx>>), @@ -477,8 +489,8 @@ pub enum SubregionOrigin<'tcx> { } // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] -static_assert_size!(SubregionOrigin<'_>, 32); +#[cfg(target_pointer_width = "64")] +rustc_data_structures::static_assert_size!(SubregionOrigin<'_>, 32); impl<'tcx> SubregionOrigin<'tcx> { pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> { @@ -527,8 +539,8 @@ pub enum RegionVariableOrigin { /// Region variables created as the values for early-bound regions. /// - /// FIXME(@lcnr): This can also store a `DefId`, similar to - /// `TypeVariableOriginKind::TypeParameterDefinition`. + /// FIXME(@lcnr): This should also store a `DefId`, similar to + /// `TypeVariableOrigin`. RegionParameterDefinition(Span, Symbol), /// Region variables created when instantiating a binder with @@ -824,21 +836,6 @@ impl<'tcx> InferCtxt<'tcx> { .collect() } - fn combine_fields<'a>( - &'a self, - trace: TypeTrace<'tcx>, - param_env: ty::ParamEnv<'tcx>, - define_opaque_types: DefineOpaqueTypes, - ) -> CombineFields<'a, 'tcx> { - CombineFields { - infcx: self, - trace, - param_env, - obligations: PredicateObligations::new(), - define_opaque_types, - } - } - pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T) -> bool where T: at::ToTrace<'tcx>, @@ -945,27 +942,14 @@ impl<'tcx> InferCtxt<'tcx> { (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { return Err((a_vid, b_vid)); } - // We don't silently want to constrain hidden types here, so we assert that either one side is - // an infer var, so it'll get constrained to whatever the other side is, or there are no opaque - // types involved. - // We don't expect this to actually get hit, but if it does, we now at least know how to write - // a test for it. - (_, ty::Infer(ty::TyVar(_))) => {} - (ty::Infer(ty::TyVar(_)), _) => {} - _ if r_a != r_b && (r_a, r_b).has_opaque_types() => { - span_bug!( - cause.span(), - "opaque types got hidden types registered from within subtype predicate: {r_a:?} vs {r_b:?}" - ) - } _ => {} } self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| { if a_is_expected { - Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::Yes, a, b)) + Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::No, a, b)) } else { - Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::Yes, b, a)) + Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::No, b, a)) } }) } @@ -988,72 +972,67 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().type_variables().num_vars() } - pub fn next_ty_var_id(&self, origin: TypeVariableOrigin) -> TyVid { - self.inner.borrow_mut().type_variables().new_var(self.universe(), origin) + pub fn next_ty_var(&self, span: Span) -> Ty<'tcx> { + self.next_ty_var_with_origin(TypeVariableOrigin { span, param_def_id: None }) } - pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - Ty::new_var(self.tcx, self.next_ty_var_id(origin)) + pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { + let vid = self.inner.borrow_mut().type_variables().new_var(self.universe(), origin); + Ty::new_var(self.tcx, vid) } - pub fn next_ty_var_id_in_universe( - &self, - origin: TypeVariableOrigin, - universe: ty::UniverseIndex, - ) -> TyVid { + pub fn next_ty_var_id_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> TyVid { + let origin = TypeVariableOrigin { span, param_def_id: None }; self.inner.borrow_mut().type_variables().new_var(universe, origin) } - pub fn next_ty_var_in_universe( - &self, - origin: TypeVariableOrigin, - universe: ty::UniverseIndex, - ) -> Ty<'tcx> { - let vid = self.next_ty_var_id_in_universe(origin, universe); + pub fn next_ty_var_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> Ty<'tcx> { + let vid = self.next_ty_var_id_in_universe(span, universe); Ty::new_var(self.tcx, vid) } - pub fn next_const_var(&self, ty: Ty<'tcx>, origin: ConstVariableOrigin) -> ty::Const<'tcx> { - ty::Const::new_var(self.tcx, self.next_const_var_id(origin), ty) + pub fn next_const_var(&self, ty: Ty<'tcx>, span: Span) -> ty::Const<'tcx> { + self.next_const_var_with_origin(ty, ConstVariableOrigin { span, param_def_id: None }) } - pub fn next_const_var_in_universe( + pub fn next_const_var_with_origin( &self, ty: Ty<'tcx>, origin: ConstVariableOrigin, - universe: ty::UniverseIndex, ) -> ty::Const<'tcx> { let vid = self .inner .borrow_mut() .const_unification_table() - .new_key(ConstVariableValue::Unknown { origin, universe }) + .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) .vid; ty::Const::new_var(self.tcx, vid, ty) } - pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid { - self.inner + pub fn next_const_var_in_universe( + &self, + ty: Ty<'tcx>, + span: Span, + universe: ty::UniverseIndex, + ) -> ty::Const<'tcx> { + let origin = ConstVariableOrigin { span, param_def_id: None }; + let vid = self + .inner .borrow_mut() .const_unification_table() - .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) - .vid - } - - fn next_int_var_id(&self) -> IntVid { - self.inner.borrow_mut().int_unification_table().new_key(None) + .new_key(ConstVariableValue::Unknown { origin, universe }) + .vid; + ty::Const::new_var(self.tcx, vid, ty) } pub fn next_int_var(&self) -> Ty<'tcx> { - Ty::new_int_var(self.tcx, self.next_int_var_id()) - } - - fn next_float_var_id(&self) -> FloatVid { - self.inner.borrow_mut().float_unification_table().new_key(None) + let vid = self.inner.borrow_mut().int_unification_table().new_key(None); + Ty::new_int_var(self.tcx, vid) } pub fn next_float_var(&self) -> Ty<'tcx> { - Ty::new_float_var(self.tcx, self.next_float_var_id()) + let vid = self.inner.borrow_mut().float_unification_table().new_key(None); + Ty::new_float_var(self.tcx, vid) } /// Creates a fresh region variable with the next available index. @@ -1467,24 +1446,13 @@ impl<'tcx> InferCtxt<'tcx> { fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> { self.map .entry(bt.var) - .or_insert_with(|| { - self.infcx - .next_ty_var(TypeVariableOrigin { param_def_id: None, span: self.span }) - .into() - }) + .or_insert_with(|| self.infcx.next_ty_var(self.span).into()) .expect_ty() } fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> { self.map .entry(bv) - .or_insert_with(|| { - self.infcx - .next_const_var( - ty, - ConstVariableOrigin { param_def_id: None, span: self.span }, - ) - .into() - }) + .or_insert_with(|| self.infcx.next_const_var(ty, self.span).into()) .expect_const() } } @@ -1521,15 +1489,6 @@ impl<'tcx> InferCtxt<'tcx> { closure_kind_ty.to_opt_closure_kind() } - /// Clears the selection, evaluation, and projection caches. This is useful when - /// repeatedly attempting to select an `Obligation` while changing only - /// its `ParamEnv`, since `FulfillmentContext` doesn't use probing. - pub fn clear_caches(&self) { - self.selection_cache.clear(); - self.evaluation_cache.clear(); - self.inner.borrow_mut().projection_cache().clear(); - } - pub fn universe(&self) -> ty::UniverseIndex { self.universe.get() } @@ -1900,7 +1859,7 @@ impl<'tcx> SubregionOrigin<'tcx> { SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span) } - traits::ObligationCauseCode::CompareImplItemObligation { + traits::ObligationCauseCode::CompareImplItem { impl_item_def_id, trait_item_def_id, kind: _, diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 94a546f87ee..8eb3185673b 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -1,4 +1,3 @@ -use super::type_variable::TypeVariableOrigin; use super::{DefineOpaqueTypes, InferResult}; use crate::errors::OpaqueHiddenTypeDiag; use crate::infer::{InferCtxt, InferOk}; @@ -65,7 +64,7 @@ impl<'tcx> InferCtxt<'tcx> { let span = if span.contains(def_span) { def_span } else { span }; let code = traits::ObligationCauseCode::OpaqueReturnType(None); let cause = ObligationCause::new(span, body_id, code); - let ty_var = self.next_ty_var(TypeVariableOrigin { param_def_id: None, span }); + let ty_var = self.next_ty_var(span); obligations.extend( self.handle_opaque_type(ty, ty_var, &cause, param_env).unwrap().obligations, ); @@ -485,6 +484,19 @@ impl<'tcx> InferCtxt<'tcx> { Ok(InferOk { value: (), obligations }) } + /// Insert a hidden type into the opaque type storage, making sure + /// it hasn't previously been defined. This does not emit any + /// constraints and it's the responsibility of the caller to make + /// sure that the item bounds of the opaque are checked. + pub fn inject_new_hidden_type_unchecked( + &self, + opaque_type_key: OpaqueTypeKey<'tcx>, + hidden_ty: OpaqueHiddenType<'tcx>, + ) { + let prev = self.inner.borrow_mut().opaque_types().register(opaque_type_key, hidden_ty); + assert_eq!(prev, None); + } + /// Insert a hidden type into the opaque type storage, equating it /// with any previous entries if necessary. /// @@ -576,7 +588,7 @@ impl<'tcx> InferCtxt<'tcx> { && !tcx.is_impl_trait_in_trait(projection_ty.def_id) && !self.next_trait_solver() => { - self.infer_projection( + self.projection_ty_to_infer( param_env, projection_ty, cause.clone(), diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index a7ddf475436..e07d181e4e0 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -1,4 +1,5 @@ use rustc_data_structures::undo_log::UndoLogs; +use rustc_middle::bug; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty}; use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog}; diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index f8dbfdde30c..5bcb4f29364 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -3,6 +3,7 @@ use crate::infer::GenericKind; use crate::traits::query::OutlivesBound; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::transitive_relation::TransitiveRelationBuilder; +use rustc_middle::bug; use rustc_middle::ty::{self, Region}; use super::explicit_outlives_bounds; @@ -63,8 +64,7 @@ struct OutlivesEnvironmentBuilder<'tcx> { /// "Region-bound pairs" tracks outlives relations that are known to /// be true, either because of explicit where-clauses like `T: 'a` or /// because of implied bounds. -pub type RegionBoundPairs<'tcx> = - FxIndexSet<ty::OutlivesPredicate<GenericKind<'tcx>, Region<'tcx>>>; +pub type RegionBoundPairs<'tcx> = FxIndexSet<ty::OutlivesPredicate<'tcx, GenericKind<'tcx>>>; impl<'tcx> OutlivesEnvironment<'tcx> { /// Create a builder using `ParamEnv` and add explicit outlives bounds into it. diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index fe323982ec0..32c790523b6 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -67,6 +67,7 @@ use crate::infer::snapshot::undo_log::UndoLog; use crate::infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound}; use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::undo_log::UndoLogs; +use rustc_middle::bug; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{ @@ -103,8 +104,12 @@ impl<'tcx> InferCtxt<'tcx> { cause.span, sup_type, match cause.code().peel_derives() { - ObligationCauseCode::BindingObligation(_, span) - | ObligationCauseCode::ExprBindingObligation(_, span, ..) => Some(*span), + ObligationCauseCode::WhereClause(_, span) + | ObligationCauseCode::WhereClauseInExpr(_, span, ..) + if !span.is_dummy() => + { + Some(*span) + } _ => None, }, ) diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index bd981c20567..7e977b9b954 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -94,7 +94,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { pub fn approx_declared_bounds_from_env( &self, alias_ty: ty::AliasTy<'tcx>, - ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> { + ) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> { let erased_alias_ty = self.tcx.erase_regions(alias_ty.to_ty(self.tcx)); self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty) } @@ -193,7 +193,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { fn declared_generic_bounds_from_env( &self, generic_ty: Ty<'tcx>, - ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> { + ) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> { assert!(matches!(generic_ty.kind(), ty::Param(_) | ty::Placeholder(_))); self.declared_generic_bounds_from_env_for_erased_ty(generic_ty) } @@ -213,7 +213,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { fn declared_generic_bounds_from_env_for_erased_ty( &self, erased_ty: Ty<'tcx>, - ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> { + ) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> { let tcx = self.tcx; // To start, collect bounds from user environment. Note that diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs index e60efe37fd9..16786347980 100644 --- a/compiler/rustc_infer/src/infer/projection.rs +++ b/compiler/rustc_infer/src/infer/projection.rs @@ -3,7 +3,6 @@ use rustc_middle::ty::{self, Ty}; use crate::traits::{Obligation, PredicateObligation}; -use super::type_variable::TypeVariableOrigin; use super::InferCtxt; impl<'tcx> InferCtxt<'tcx> { @@ -13,7 +12,7 @@ impl<'tcx> InferCtxt<'tcx> { /// of the given projection. This allows us to proceed with projections /// while they cannot be resolved yet due to missing information or /// simply due to the lack of access to the trait resolution machinery. - pub fn infer_projection( + pub fn projection_ty_to_infer( &self, param_env: ty::ParamEnv<'tcx>, projection_ty: ty::AliasTy<'tcx>, @@ -23,12 +22,9 @@ impl<'tcx> InferCtxt<'tcx> { ) -> Ty<'tcx> { debug_assert!(!self.next_trait_solver()); let def_id = projection_ty.def_id; - let ty_var = self.next_ty_var(TypeVariableOrigin { - param_def_id: None, - span: self.tcx.def_span(def_id), - }); + let ty_var = self.next_ty_var(self.tcx.def_span(def_id)); let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection( - ty::ProjectionPredicate { projection_ty, term: ty_var.into() }, + ty::ProjectionPredicate { projection_term: projection_ty.into(), term: ty_var.into() }, ))); let obligation = Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection); diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 06f8dd4a4c6..255ca52d3e9 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -3,6 +3,7 @@ use crate::infer::snapshot::CombinedSnapshot; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph::{scc::Sccs, vec_graph::VecGraph}; use rustc_index::Idx; +use rustc_middle::span_bug; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::RelateResult; @@ -382,7 +383,7 @@ impl<'tcx> MiniGraph<'tcx> { edges.push((source_node, target_node)); }, ); - let graph = VecGraph::new(nodes.len(), edges); + let graph = VecGraph::<_, false>::new(nodes.len(), edges); let sccs = Sccs::new(&graph); Self { nodes, sccs } } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 3d6b54721d0..6f755e07ff1 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -11,11 +11,13 @@ use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify as ut; use rustc_index::IndexVec; +use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::infer::unify_key::{RegionVariableValue, RegionVidKey}; use rustc_middle::ty::ReStatic; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ReBound, ReVar}; use rustc_middle::ty::{Region, RegionVid}; +use rustc_middle::{bug, span_bug}; use rustc_span::Span; use std::ops::Range; diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 8a3125f9ded..6b41e450684 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -22,13 +22,14 @@ use super::glb::Glb; use super::lub::Lub; use super::type_relating::TypeRelating; use super::StructurallyRelateAliases; -use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace}; +use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; -use rustc_middle::infer::canonical::OriginalQueryValues; +use rustc_middle::bug; use rustc_middle::infer::unify_key::EffectVarValue; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::relate::{RelateResult, TypeRelation}; -use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast}; use rustc_middle::ty::{IntType, UintType}; use rustc_span::Span; @@ -41,6 +42,17 @@ pub struct CombineFields<'infcx, 'tcx> { pub define_opaque_types: DefineOpaqueTypes, } +impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { + pub fn new( + infcx: &'infcx InferCtxt<'tcx>, + trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, + define_opaque_types: DefineOpaqueTypes, + ) -> Self { + Self { infcx, trace, param_env, define_opaque_types, obligations: vec![] } + } +} + impl<'tcx> InferCtxt<'tcx> { pub fn super_combine_tys<R>( &self, @@ -158,36 +170,11 @@ impl<'tcx> InferCtxt<'tcx> { let a = self.shallow_resolve_const(a); let b = self.shallow_resolve_const(b); - // We should never have to relate the `ty` field on `Const` as it is checked elsewhere that consts have the - // correct type for the generic param they are an argument for. However there have been a number of cases - // historically where asserting that the types are equal has found bugs in the compiler so this is valuable - // to check even if it is a bit nasty impl wise :( - // - // This probe is probably not strictly necessary but it seems better to be safe and not accidentally find - // ourselves with a check to find bugs being required for code to compile because it made inference progress. - self.probe(|_| { - if a.ty() == b.ty() { - return; - } - - // We don't have access to trait solving machinery in `rustc_infer` so the logic for determining if the - // two const param's types are able to be equal has to go through a canonical query with the actual logic - // in `rustc_trait_selection`. - let canonical = self.canonicalize_query( - relation.param_env().and((a.ty(), b.ty())), - &mut OriginalQueryValues::default(), - ); - self.tcx.check_tys_might_be_eq(canonical).unwrap_or_else(|_| { - // The error will only be reported later. If we emit an ErrorGuaranteed - // here, then we will never get to the code that actually emits the error. - self.tcx.dcx().delayed_bug(format!( - "cannot relate consts of different types (a={a:?}, b={b:?})", - )); - // We treat these constants as if they were of the same type, so that any - // such constants being used in impls make these impls match barring other mismatches. - // This helps with diagnostics down the road. - }); - }); + // It is always an error if the types of two constants that are related are not equal. + let InferOk { value: (), obligations } = self + .at(&ObligationCause::dummy_with_span(relation.span()), relation.param_env()) + .eq(DefineOpaqueTypes::No, a.ty(), b.ty())?; + relation.register_obligations(obligations); match (a.kind(), b.kind()) { ( @@ -336,7 +323,10 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { self.obligations.extend(obligations); } - pub fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>) { + pub fn register_predicates( + &mut self, + obligations: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>, + ) { self.obligations.extend(obligations.into_iter().map(|to_pred| { Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, to_pred) })) @@ -359,7 +349,10 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { /// Register predicates that must hold in order for this relation to hold. Uses /// a default obligation cause, [`ObligationEmittingRelation::register_obligations`] should /// be used if control over the obligation causes is required. - fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>); + fn register_predicates( + &mut self, + obligations: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>, + ); /// Register `AliasRelate` obligation(s) that both types must be related to each other. fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>); diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 74929daffe2..d4c7d752c95 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -1,11 +1,12 @@ use std::mem; use super::StructurallyRelateAliases; -use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableValue}; +use crate::infer::type_variable::TypeVariableValue; use crate::infer::{InferCtxt, ObligationEmittingRelation, RegionVariableOrigin}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; +use rustc_middle::bug; use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; @@ -101,7 +102,7 @@ impl<'tcx> InferCtxt<'tcx> { // instead create a new inference variable `?normalized_source`, emitting // `Projection(normalized_source, ?ty_normalized)` and `?normalized_source <: generalized_ty`. relation.register_predicates([ty::ProjectionPredicate { - projection_ty: data, + projection_term: data.into(), term: generalized_ty.into(), }]); } @@ -350,11 +351,14 @@ impl<'tcx> Generalizer<'_, 'tcx> { &mut self, alias: ty::AliasTy<'tcx>, ) -> Result<Ty<'tcx>, TypeError<'tcx>> { - if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() { - return Ok(self.infcx.next_ty_var_in_universe( - TypeVariableOrigin { param_def_id: None, span: self.span }, - self.for_universe, - )); + // We do not eagerly replace aliases with inference variables if they have + // escaping bound vars, see the method comment for details. However, when we + // are inside of an alias with escaping bound vars replacing nested aliases + // with inference variables can cause incorrect ambiguity. + // + // cc trait-system-refactor-initiative#110 + if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias { + return Ok(self.infcx.next_ty_var_in_universe(self.span, self.for_universe)); } let is_nested_alias = mem::replace(&mut self.in_alias, true); @@ -374,10 +378,7 @@ impl<'tcx> Generalizer<'_, 'tcx> { } debug!("generalization failure in alias"); - Ok(self.infcx.next_ty_var_in_universe( - TypeVariableOrigin { param_def_id: None, span: self.span }, - self.for_universe, - )) + Ok(self.infcx.next_ty_var_in_universe(self.span, self.for_universe)) } } }; @@ -492,9 +493,30 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { let origin = inner.type_variables().var_origin(vid); let new_var_id = inner.type_variables().new_var(self.for_universe, origin); - let u = Ty::new_var(self.tcx(), new_var_id); - debug!("replacing original vid={:?} with new={:?}", vid, u); - Ok(u) + // If we're in the new solver and create a new inference + // variable inside of an alias we eagerly constrain that + // inference variable to prevent unexpected ambiguity errors. + // + // This is incomplete as it pulls down the universe of the + // original inference variable, even though the alias could + // normalize to a type which does not refer to that type at + // all. I don't expect this to cause unexpected errors in + // practice. + // + // We only need to do so for type and const variables, as + // region variables do not impact normalization, and will get + // correctly constrained by `AliasRelate` later on. + // + // cc trait-system-refactor-initiative#108 + if self.infcx.next_trait_solver() + && !self.infcx.intercrate + && self.in_alias + { + inner.type_variables().equate(vid, new_var_id); + } + + debug!("replacing original vid={:?} with new={:?}", vid, new_var_id); + Ok(Ty::new_var(self.tcx(), new_var_id)) } } } @@ -614,6 +636,15 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { universe: self.for_universe, }) .vid; + + // See the comment for type inference variables + // for more details. + if self.infcx.next_trait_solver() + && !self.infcx.intercrate + && self.in_alias + { + variable_table.union(vid, new_var_id); + } Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty())) } } diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs index b86d1b2671d..a224a86492a 100644 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ b/compiler/rustc_infer/src/infer/relate/glb.rs @@ -140,7 +140,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> { self.fields.param_env } - fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) { + fn register_predicates( + &mut self, + obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>, + ) { self.fields.register_predicates(obligations); } diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index f9470c9b8f6..38e25b0d9b6 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -18,7 +18,6 @@ //! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order) use super::combine::ObligationEmittingRelation; -use crate::infer::type_variable::TypeVariableOrigin; use crate::infer::{DefineOpaqueTypes, InferCtxt}; use crate::traits::ObligationCause; @@ -88,14 +87,12 @@ where // iterate on the subtype obligations that are returned, but I // think this suffices. -nmatsakis (&ty::Infer(TyVar(..)), _) => { - let v = infcx - .next_ty_var(TypeVariableOrigin { param_def_id: None, span: this.cause().span }); + let v = infcx.next_ty_var(this.cause().span); this.relate_bound(v, b, a)?; Ok(v) } (_, &ty::Infer(TyVar(..))) => { - let v = infcx - .next_ty_var(TypeVariableOrigin { param_def_id: None, span: this.cause().span }); + let v = infcx.next_ty_var(this.cause().span); this.relate_bound(v, a, b)?; Ok(v) } diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs index 20f5f65c984..83ab7770770 100644 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ b/compiler/rustc_infer/src/infer/relate/lub.rs @@ -140,7 +140,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> { self.fields.param_env } - fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) { + fn register_predicates( + &mut self, + obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>, + ) { self.fields.register_predicates(obligations); } diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index 86a24eef7f5..21064fff97f 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -312,7 +312,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for TypeRelating<'_, '_, 'tcx> { self.structurally_relate_aliases } - fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) { + fn register_predicates( + &mut self, + obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>, + ) { self.fields.register_predicates(obligations); } diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 758aac004dc..21ef2e89523 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -1,4 +1,5 @@ use super::{FixupError, FixupResult, InferCtxt}; +use rustc_middle::bug; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable}; @@ -172,84 +173,3 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> { } } } - -/////////////////////////////////////////////////////////////////////////// -// EAGER RESOLUTION - -/// Resolves ty, region, and const vars to their inferred values or their root vars. -pub struct EagerResolver<'a, 'tcx> { - infcx: &'a InferCtxt<'tcx>, -} - -impl<'a, 'tcx> EagerResolver<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { - EagerResolver { infcx } - } -} - -impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerResolver<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match *t.kind() { - ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) { - Ok(t) => t.fold_with(self), - Err(_) => Ty::new_var(self.infcx.tcx, self.infcx.root_var(vid)), - }, - ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid), - ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid), - _ => { - if t.has_infer() { - t.super_fold_with(self) - } else { - t - } - } - } - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { - ty::ReVar(vid) => self - .infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .opportunistic_resolve_var(self.infcx.tcx, vid), - _ => r, - } - } - - fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { - match c.kind() { - ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { - // FIXME: we need to fold the ty too, I think. - match self.infcx.probe_const_var(vid) { - Ok(c) => c.fold_with(self), - Err(_) => { - ty::Const::new_var(self.infcx.tcx, self.infcx.root_const_var(vid), c.ty()) - } - } - } - ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => { - debug_assert_eq!(c.ty(), self.infcx.tcx.types.bool); - self.infcx.probe_effect_var(vid).unwrap_or_else(|| { - ty::Const::new_infer( - self.infcx.tcx, - ty::InferConst::EffectVar(self.infcx.root_effect_var(vid)), - self.infcx.tcx.types.bool, - ) - }) - } - _ => { - if c.has_infer() { - c.super_fold_with(self) - } else { - c - } - } - } - } -} diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index 83667f7276d..4408251c99d 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -195,7 +195,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> { // Recreate it with a fresh variable here. let idx = vid.as_usize() - self.type_vars.0.start.as_usize(); let origin = self.type_vars.1[idx]; - self.infcx.next_ty_var(origin) + self.infcx.next_ty_var_with_origin(origin) } else { // This variable was created before the // "fudging". Since we refresh all type @@ -244,7 +244,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> { // Recreate it with a fresh variable here. let idx = vid.index() - self.const_vars.0.start.index(); let origin = self.const_vars.1[idx]; - self.infcx.next_const_var(ct.ty(), origin) + self.infcx.next_const_var_with_origin(ct.ty(), origin) } else { ct } diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 96afa257ebb..b56b39e61f0 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -1,6 +1,7 @@ use rustc_data_structures::undo_log::Rollback; use rustc_hir::def_id::DefId; use rustc_index::IndexVec; +use rustc_middle::bug; use rustc_middle::ty::{self, Ty, TyVid}; use rustc_span::Span; diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 0444cbe2ee4..28d908abf83 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -18,7 +18,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(extend_one)] @@ -31,14 +30,7 @@ #![recursion_limit = "512"] // For rustdoc #[macro_use] -extern crate rustc_macros; -#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] -#[macro_use] -extern crate rustc_data_structures; -#[macro_use] extern crate tracing; -#[macro_use] -extern crate rustc_middle; mod errors; pub mod infer; diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index c495810858f..e27e6a0a4a1 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -1,7 +1,8 @@ use crate::infer::InferCtxt; use crate::traits::Obligation; use rustc_hir::def_id::DefId; -use rustc_middle::ty::{self, ToPredicate, Ty}; +use rustc_macros::extension; +use rustc_middle::ty::{self, Ty, Upcast}; use super::FulfillmentError; use super::{ObligationCause, PredicateObligation}; @@ -25,7 +26,7 @@ pub trait TraitEngine<'tcx>: 'tcx { cause, recursion_depth: 0, param_env, - predicate: ty::Binder::dummy(trait_ref).to_predicate(infcx.tcx), + predicate: trait_ref.upcast(infcx.tcx), }, ); } diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 94ad0f5b1c8..0ae4340098b 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -16,7 +16,7 @@ use rustc_hir as hir; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::Certainty; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, Const, ToPredicate, Ty, TyCtxt}; +use rustc_middle::ty::{self, Const, Ty, TyCtxt, Upcast}; use rustc_span::Span; pub use self::ImplSource::*; @@ -27,7 +27,7 @@ pub use self::engine::{TraitEngine, TraitEngineExt}; pub use self::project::MismatchedProjectionTypes; pub(crate) use self::project::UndoLog; pub use self::project::{ - Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, + Normalized, NormalizedTerm, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, ProjectionCacheStorage, Reveal, }; pub use rustc_middle::traits::*; @@ -105,15 +105,15 @@ impl<'tcx> PredicateObligation<'tcx> { impl<'tcx> PolyTraitObligation<'tcx> { pub fn derived_cause( &self, - variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, + variant: impl FnOnce(DerivedCause<'tcx>) -> ObligationCauseCode<'tcx>, ) -> ObligationCause<'tcx> { self.cause.clone().derived_cause(self.predicate, variant) } } // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] -static_assert_size!(PredicateObligation<'_>, 48); +#[cfg(target_pointer_width = "64")] +rustc_data_structures::static_assert_size!(PredicateObligation<'_>, 48); pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>; @@ -138,10 +138,10 @@ pub enum FulfillmentErrorCode<'tcx> { /// Inherently impossible to fulfill; this trait is implemented if and only /// if it is already implemented. Cycle(Vec<PredicateObligation<'tcx>>), - SelectionError(SelectionError<'tcx>), - ProjectionError(MismatchedProjectionTypes<'tcx>), - SubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate - ConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>), + Select(SelectionError<'tcx>), + Project(MismatchedProjectionTypes<'tcx>), + Subtype(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate + ConstEquate(ExpectedFound<Const<'tcx>>, TypeError<'tcx>), Ambiguity { /// Overflow is only `Some(suggest_recursion_limit)` when using the next generation /// trait solver `-Znext-solver`. With the old solver overflow is eagerly handled by @@ -155,7 +155,7 @@ impl<'tcx, O> Obligation<'tcx, O> { tcx: TyCtxt<'tcx>, cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - predicate: impl ToPredicate<'tcx, O>, + predicate: impl Upcast<TyCtxt<'tcx>, O>, ) -> Obligation<'tcx, O> { Self::with_depth(tcx, cause, 0, param_env, predicate) } @@ -173,9 +173,9 @@ impl<'tcx, O> Obligation<'tcx, O> { cause: ObligationCause<'tcx>, recursion_depth: usize, param_env: ty::ParamEnv<'tcx>, - predicate: impl ToPredicate<'tcx, O>, + predicate: impl Upcast<TyCtxt<'tcx>, O>, ) -> Obligation<'tcx, O> { - let predicate = predicate.to_predicate(tcx); + let predicate = predicate.upcast(tcx); Obligation { cause, param_env, recursion_depth, predicate } } @@ -184,7 +184,7 @@ impl<'tcx, O> Obligation<'tcx, O> { span: Span, body_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, - trait_ref: impl ToPredicate<'tcx, O>, + trait_ref: impl Upcast<TyCtxt<'tcx>, O>, ) -> Obligation<'tcx, O> { Obligation::new(tcx, ObligationCause::misc(span, body_id), param_env, trait_ref) } @@ -192,7 +192,7 @@ impl<'tcx, O> Obligation<'tcx, O> { pub fn with<P>( &self, tcx: TyCtxt<'tcx>, - value: impl ToPredicate<'tcx, P>, + value: impl Upcast<TyCtxt<'tcx>, P>, ) -> Obligation<'tcx, P> { Obligation::with_depth(tcx, self.cause.clone(), self.recursion_depth, self.param_env, value) } @@ -206,6 +206,18 @@ impl<'tcx> FulfillmentError<'tcx> { ) -> FulfillmentError<'tcx> { FulfillmentError { obligation, code, root_obligation } } + + pub fn is_true_error(&self) -> bool { + match self.code { + FulfillmentErrorCode::Select(_) + | FulfillmentErrorCode::Project(_) + | FulfillmentErrorCode::Subtype(_, _) + | FulfillmentErrorCode::ConstEquate(_, _) => true, + FulfillmentErrorCode::Cycle(_) | FulfillmentErrorCode::Ambiguity { overflow: _ } => { + false + } + } + } } impl<'tcx> PolyTraitObligation<'tcx> { diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs index 31ceb234332..b696264aab0 100644 --- a/compiler/rustc_infer/src/traits/project.rs +++ b/compiler/rustc_infer/src/traits/project.rs @@ -8,7 +8,7 @@ use rustc_data_structures::{ snapshot_map::{self, SnapshotMapRef, SnapshotMapStorage}, undo_log::Rollback, }; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty; pub use rustc_middle::traits::{EvaluationResult, Reveal}; @@ -26,7 +26,7 @@ pub struct Normalized<'tcx, T> { pub obligations: Vec<PredicateObligation<'tcx>>, } -pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>; +pub type NormalizedTerm<'tcx> = Normalized<'tcx, ty::Term<'tcx>>; impl<'tcx, T> Normalized<'tcx, T> { pub fn with<U>(self, value: U) -> Normalized<'tcx, U> { @@ -77,12 +77,13 @@ pub struct ProjectionCacheStorage<'tcx> { #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct ProjectionCacheKey<'tcx> { - ty: ty::AliasTy<'tcx>, + term: ty::AliasTerm<'tcx>, + param_env: ty::ParamEnv<'tcx>, } impl<'tcx> ProjectionCacheKey<'tcx> { - pub fn new(ty: ty::AliasTy<'tcx>) -> Self { - Self { ty } + pub fn new(term: ty::AliasTerm<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { + Self { term, param_env } } } @@ -92,8 +93,8 @@ pub enum ProjectionCacheEntry<'tcx> { Ambiguous, Recur, Error, - NormalizedTy { - ty: Normalized<'tcx, ty::Term<'tcx>>, + NormalizedTerm { + ty: NormalizedTerm<'tcx>, /// If we were able to successfully evaluate the /// corresponding cache entry key during predicate /// evaluation, then this field stores the final @@ -174,11 +175,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> { } /// Indicates that `key` was normalized to `value`. - pub fn insert_term( - &mut self, - key: ProjectionCacheKey<'tcx>, - value: Normalized<'tcx, ty::Term<'tcx>>, - ) { + pub fn insert_term(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTerm<'tcx>) { debug!( "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}", key, value @@ -189,7 +186,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> { return; } let fresh_key = - map.insert(key, ProjectionCacheEntry::NormalizedTy { ty: value, complete: None }); + map.insert(key, ProjectionCacheEntry::NormalizedTerm { ty: value, complete: None }); assert!(!fresh_key, "never started projecting `{key:?}`"); } @@ -200,13 +197,16 @@ impl<'tcx> ProjectionCache<'_, 'tcx> { pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>, result: EvaluationResult) { let mut map = self.map(); match map.get(&key) { - Some(ProjectionCacheEntry::NormalizedTy { ty, complete: _ }) => { + Some(ProjectionCacheEntry::NormalizedTerm { ty, complete: _ }) => { info!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty); let mut ty = ty.clone(); if result.must_apply_considering_regions() { ty.obligations = vec![]; } - map.insert(key, ProjectionCacheEntry::NormalizedTy { ty, complete: Some(result) }); + map.insert( + key, + ProjectionCacheEntry::NormalizedTerm { ty, complete: Some(result) }, + ); } ref value => { // Type inference could "strand behind" old cache entries. Leave @@ -218,7 +218,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> { pub fn is_complete(&mut self, key: ProjectionCacheKey<'tcx>) -> Option<EvaluationResult> { self.map().get(&key).and_then(|res| match res { - ProjectionCacheEntry::NormalizedTy { ty: _, complete } => *complete, + ProjectionCacheEntry::NormalizedTerm { ty: _, complete } => *complete, _ => None, }) } diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index 064e09b8750..b616d37e5b5 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -39,12 +39,12 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use traits::FulfillmentErrorCode::*; match *self { - SelectionError(ref e) => write!(f, "{e:?}"), - ProjectionError(ref e) => write!(f, "{e:?}"), - SubtypeError(ref a, ref b) => { + Select(ref e) => write!(f, "{e:?}"), + Project(ref e) => write!(f, "{e:?}"), + Subtype(ref a, ref b) => { write!(f, "CodeSubtypeError({a:?}, {b:?})") } - ConstEquateError(ref a, ref b) => { + ConstEquate(ref a, ref b) => { write!(f, "CodeConstEquateError({a:?}, {b:?})") } Ambiguity { overflow: None } => write!(f, "Ambiguity"), diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 6d43011d33c..cc12a4bf091 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,9 +1,9 @@ use smallvec::smallvec; use crate::infer::outlives::components::{push_outlives_components, Component}; -use crate::traits::{self, Obligation, PredicateObligation}; +use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation}; use rustc_data_structures::fx::FxHashSet; -use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -129,7 +129,7 @@ impl<'tcx> Elaboratable<'tcx> for PredicateObligation<'tcx> { index: usize, ) -> Self { let cause = self.cause.clone().derived_cause(parent_trait_pred, |derived| { - traits::ImplDerivedObligation(Box::new(traits::ImplDerivedObligationCause { + ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause { derived, impl_or_alias_def_id: parent_trait_pred.def_id(), impl_def_predicate_index: Some(index), @@ -357,9 +357,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { None } }) - .map(|clause| { - elaboratable.child(bound_clause.rebind(clause).to_predicate(tcx)) - }), + .map(|clause| elaboratable.child(bound_clause.rebind(clause).upcast(tcx))), ); } ty::ClauseKind::RegionOutlives(..) => { @@ -409,14 +407,14 @@ pub fn supertraits<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> { - elaborate(tcx, [trait_ref.to_predicate(tcx)]).filter_only_self().filter_to_traits() + elaborate(tcx, [trait_ref.upcast(tcx)]).filter_only_self().filter_to_traits() } pub fn transitive_bounds<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>, ) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> { - elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx))) + elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx))) .filter_only_self() .filter_to_traits() } @@ -431,7 +429,7 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>( trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>, assoc_name: Ident, ) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> { - elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx))) + elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx))) .filter_only_self_that_defines(assoc_name) .filter_to_traits() } @@ -457,7 +455,7 @@ impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits< fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> { while let Some(pred) = self.base_iterator.next() { - if let Some(data) = pred.to_opt_poly_trait_pred() { + if let Some(data) = pred.as_trait_clause() { return Some(data.map_bound(|t| t.trait_ref)); } } |
