diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-07 05:48:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-07 05:48:48 +0000 |
commit | ef24de24a82fe681581cc130f342363c47c0969a (patch) | |
tree | 0d494f7e1a38b95c92426f58fe6eaa877303a86c /compiler/rustc_hir_analysis/src/check | |
parent | Releasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip |
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_analysis/src/check')
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/check.rs | 101 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/compare_impl_item.rs | 342 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs | 8 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/entry.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/mod.rs | 7 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/region.rs | 4 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/wfcheck.rs | 339 |
7 files changed, 432 insertions, 371 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 44e1bdb83..e61ca232d 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -128,7 +128,11 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b let param_env = tcx.param_env(item_def_id); for field in &def.non_enum_variant().fields { - let field_ty = tcx.normalize_erasing_regions(param_env, field.ty(tcx, args)); + let Ok(field_ty) = tcx.try_normalize_erasing_regions(param_env, field.ty(tcx, args)) + else { + tcx.sess.delay_span_bug(span, "could not normalize field type"); + continue; + }; if !allowed_union_field(field_ty, tcx, param_env) { let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) { @@ -291,7 +295,7 @@ fn check_opaque_meets_bounds<'tcx>( let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args); - // `ReErased` regions appear in the "parent_args" of closures/generators. + // `ReErased` regions appear in the "parent_args" of closures/coroutines. // We're ignoring them here and replacing them with fresh region variables. // See tests in ui/type-alias-impl-trait/closure_{parent_args,wf_outlives}.rs. // @@ -327,7 +331,7 @@ fn check_opaque_meets_bounds<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let guar = infcx.err_ctxt().report_fulfillment_errors(&errors); + let guar = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(guar); } match origin { @@ -481,8 +485,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { fn_maybe_err(tcx, assoc_item.ident(tcx).span, abi); } ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => { - let trait_args = - GenericArgs::identity_for_item(tcx, id.owner_id); + let trait_args = GenericArgs::identity_for_item(tcx, id.owner_id); let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds( tcx, assoc_item, @@ -502,7 +505,8 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { } DefKind::OpaqueTy => { let origin = tcx.opaque_type_origin(id.owner_id.def_id); - if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin + if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) + | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin && let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id) && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() { @@ -589,7 +593,9 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { } DefKind::GlobalAsm => { let it = tcx.hir().item(id); - let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) }; + let hir::ItemKind::GlobalAsm(asm) = it.kind else { + span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) + }; InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.owner_id.def_id); } _ => {} @@ -783,21 +789,21 @@ fn check_impl_items_against_trait<'tcx>( let (msg, feature) = if tcx.asyncness(def_id).is_async() { ( format!("async {descr} in trait cannot be specialized"), - sym::async_fn_in_trait, + "async functions in traits", ) } else { ( format!( "{descr} with return-position `impl Trait` in trait cannot be specialized" ), - sym::return_position_impl_trait_in_trait, + "return position `impl Trait` in traits", ) }; tcx.sess .struct_span_err(tcx.def_span(def_id), msg) .note(format!( "specialization behaves in inconsistent and \ - surprising ways with `#![feature({feature})]`, \ + surprising ways with {feature}, \ and for now is disallowed" )) .emit(); @@ -873,10 +879,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct<T>([T; N]) through, let monomorphization catch errors ty::Array(t, _clen) - if matches!( - t.kind(), - ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) - ) => + if matches!(t.kind(), ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)) => { /* struct([f32; 4]) is ok */ } _ => { struct_span_err!( @@ -899,17 +902,17 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { for attr in tcx.get_attrs(def.did(), sym::repr) { for r in attr::parse_repr_attr(&tcx.sess, attr) { if let attr::ReprPacked(pack) = r - && let Some(repr_pack) = repr.pack - && pack as u64 != repr_pack.bytes() - { - struct_span_err!( - tcx.sess, - sp, - E0634, - "type has conflicting packed representation hints" - ) - .emit(); - } + && let Some(repr_pack) = repr.pack + && pack as u64 != repr_pack.bytes() + { + struct_span_err!( + tcx.sess, + sp, + E0634, + "type has conflicting packed representation hints" + ) + .emit(); + } } } if repr.align.is_some() { @@ -1174,7 +1177,8 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) let (span, display_discr) = match var.discr { ty::VariantDiscr::Explicit(discr_def_id) => { // In the case the discriminant is both a duplicate and overflowed, let the user know - if let hir::Node::AnonConst(expr) = tcx.hir().get_by_def_id(discr_def_id.expect_local()) + if let hir::Node::AnonConst(expr) = + tcx.hir().get_by_def_id(discr_def_id.expect_local()) && let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node && *lit_value != dis.val @@ -1303,15 +1307,9 @@ pub(super) fn check_type_params_are_used<'tcx>( && let ty::GenericParamDefKind::Type { .. } = param.kind { let span = tcx.def_span(param.def_id); - struct_span_err!( - tcx.sess, - span, - E0091, - "type parameter `{}` is unused", - param.name, - ) - .span_label(span, "unused type parameter") - .emit(); + struct_span_err!(tcx.sess, span, E0091, "type parameter `{}` is unused", param.name,) + .span_label(span, "unused type parameter") + .emit(); } } } @@ -1400,7 +1398,7 @@ fn opaque_type_cycle_error( self.opaques.push(def); ControlFlow::Continue(()) } - ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => { + ty::Closure(def_id, ..) | ty::Coroutine(def_id, ..) => { self.closures.push(def_id); t.super_visit_with(self) } @@ -1430,7 +1428,10 @@ fn opaque_type_cycle_error( let mut label_match = |ty: Ty<'_>, span| { for arg in ty.walk() { if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: captured_def_id, .. }) = *ty.kind() + && let ty::Alias( + ty::Opaque, + ty::AliasTy { def_id: captured_def_id, .. }, + ) = *ty.kind() && captured_def_id == opaque_def_id.to_def_id() { err.span_label( @@ -1449,11 +1450,11 @@ fn opaque_type_cycle_error( { label_match(capture.place.ty(), capture.get_path_span(tcx)); } - // Label any generator locals that capture the opaque - if let DefKind::Generator = tcx.def_kind(closure_def_id) - && let Some(generator_layout) = tcx.mir_generator_witnesses(closure_def_id) + // Label any coroutine locals that capture the opaque + if let DefKind::Coroutine = tcx.def_kind(closure_def_id) + && let Some(coroutine_layout) = tcx.mir_coroutine_witnesses(closure_def_id) { - for interior_ty in &generator_layout.field_tys { + for interior_ty in &coroutine_layout.field_tys { label_match(interior_ty.ty, interior_ty.source_info.span); } } @@ -1467,14 +1468,14 @@ fn opaque_type_cycle_error( err.emit() } -pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { - debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Generator)); +pub(super) fn check_coroutine_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { + debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Coroutine)); let typeck = tcx.typeck(def_id); let param_env = tcx.param_env(def_id); - let generator_interior_predicates = &typeck.generator_interior_predicates[&def_id]; - debug!(?generator_interior_predicates); + let coroutine_interior_predicates = &typeck.coroutine_interior_predicates[&def_id]; + debug!(?coroutine_interior_predicates); let infcx = tcx .infer_ctxt() @@ -1486,15 +1487,15 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { .build(); let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(&infcx); - for (predicate, cause) in generator_interior_predicates { + for (predicate, cause) in coroutine_interior_predicates { let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate); fulfillment_cx.register_predicate_obligation(&infcx, obligation); } if (tcx.features().unsized_locals || tcx.features().unsized_fn_params) - && let Some(generator) = tcx.mir_generator_witnesses(def_id) + && let Some(coroutine) = tcx.mir_coroutine_witnesses(def_id) { - for field_ty in generator.field_tys.iter() { + for field_ty in coroutine.field_tys.iter() { fulfillment_cx.register_bound( &infcx, param_env, @@ -1503,7 +1504,7 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { ObligationCause::new( field_ty.source_info.span, def_id, - ObligationCauseCode::SizedGeneratorInterior(def_id), + ObligationCauseCode::SizedCoroutineInterior(def_id), ), ); } @@ -1512,6 +1513,6 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { let errors = fulfillment_cx.select_all_or_error(&infcx); debug!(?errors); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors); + infcx.err_ctxt().report_fulfillment_errors(errors); } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index d081b0e35..857515f97 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -16,6 +16,7 @@ use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::util::ExplicitSelf; +use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{ self, GenericArgs, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; @@ -322,7 +323,7 @@ fn compare_method_predicate_entailment<'tcx>( // FIXME(-Ztrait-solver=next): Not needed when the hack below is removed. let errors = ocx.select_where_possible(); if !errors.is_empty() { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(reported); } @@ -393,7 +394,7 @@ fn compare_method_predicate_entailment<'tcx>( }); } CheckImpliedWfMode::Skip => { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(reported); } } @@ -632,8 +633,6 @@ fn compare_asyncness<'tcx>( /// For example, given the sample code: /// /// ``` -/// #![feature(return_position_impl_trait_in_trait)] -/// /// use std::ops::Deref; /// /// trait Foo { @@ -873,7 +872,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // RPITs. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(reported); } @@ -1010,7 +1009,11 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> { }); self.types.insert(proj.def_id, (infer_ty, proj.args)); // Recurse into bounds - for (pred, pred_span) in self.interner().explicit_item_bounds(proj.def_id).iter_instantiated_copied(self.interner(), proj.args) { + for (pred, pred_span) in self + .interner() + .explicit_item_bounds(proj.def_id) + .iter_instantiated_copied(self.interner(), proj.args) + { let pred = pred.fold_with(self); let pred = self.ocx.normalize( &ObligationCause::misc(self.span, self.body_id), @@ -1181,14 +1184,15 @@ fn report_trait_method_mismatch<'tcx>( if trait_sig.inputs().len() == *i { // Suggestion to change output type. We do not suggest in `async` functions // to avoid complex logic or incorrect output. - if let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind + if let ImplItemKind::Fn(sig, _) = + &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind && !sig.header.asyncness.is_async() { let msg = "change the output type to match the trait"; let ap = Applicability::MachineApplicable; match sig.decl.output { hir::FnRetTy::DefaultReturn(sp) => { - let sugg = format!("-> {} ", trait_sig.output()); + let sugg = format!(" -> {}", trait_sig.output()); diag.span_suggestion_verbose(sp, msg, sugg, ap); } hir::FnRetTy::Return(hir_ty) => { @@ -1553,38 +1557,24 @@ fn compare_number_of_generics<'tcx>( DiagnosticId::Error("E0049".into()), ); - let mut suffix = None; - + let msg = + format!("expected {trait_count} {kind} parameter{}", pluralize!(trait_count),); if let Some(spans) = trait_spans { let mut spans = spans.iter(); if let Some(span) = spans.next() { - err.span_label( - *span, - format!( - "expected {} {} parameter{}", - trait_count, - kind, - pluralize!(trait_count), - ), - ); + err.span_label(*span, msg); } for span in spans { err.span_label(*span, ""); } } else { - suffix = Some(format!(", expected {trait_count}")); + err.span_label(tcx.def_span(trait_.def_id), msg); } if let Some(span) = span { err.span_label( span, - format!( - "found {} {} parameter{}{}", - impl_count, - kind, - pluralize!(impl_count), - suffix.unwrap_or_default(), - ), + format!("found {} {} parameter{}", impl_count, kind, pluralize!(impl_count),), ); } @@ -2049,7 +2039,7 @@ fn compare_const_predicate_entailment<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - return Err(infcx.err_ctxt().report_fulfillment_errors(&errors)); + return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); } let outlives_env = OutlivesEnvironment::new(param_env); @@ -2142,7 +2132,7 @@ fn compare_type_predicate_entailment<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(reported); } @@ -2173,127 +2163,9 @@ pub(super) fn check_type_bounds<'tcx>( impl_trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { let param_env = tcx.param_env(impl_ty.def_id); - let container_id = impl_ty.container_id(tcx); - // Given - // - // impl<A, B> Foo<u32> for (A, B) { - // type Bar<C> = Wrapper<A, B, C> - // } - // - // - `impl_trait_ref` would be `<(A, B) as Foo<u32>>` - // - `normalize_impl_ty_args` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0) - // - `normalize_impl_ty` would be `Wrapper<A, B, ^0.0>` - // - `rebased_args` would be `[(A, B), u32, ^0.0]`, combining the args from - // the *trait* with the generic associated type parameters (as bound vars). - // - // A note regarding the use of bound vars here: - // Imagine as an example - // ``` - // trait Family { - // type Member<C: Eq>; - // } - // - // impl Family for VecFamily { - // type Member<C: Eq> = i32; - // } - // ``` - // Here, we would generate - // ```notrust - // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) } - // ``` - // when we really would like to generate - // ```notrust - // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) } - // ``` - // But, this is probably fine, because although the first clause can be used with types C that - // do not implement Eq, for it to cause some kind of problem, there would have to be a - // VecFamily::Member<X> for some type X where !(X: Eq), that appears in the value of type - // Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing - // elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in - // the trait (notably, that X: Eq and T: Family). - let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = - smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len()); - // Extend the impl's identity args with late-bound GAT vars - let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id).extend_to( - tcx, - impl_ty.def_id, - |param, _| match param.kind { - GenericParamDefKind::Type { .. } => { - let kind = ty::BoundTyKind::Param(param.def_id, param.name); - let bound_var = ty::BoundVariableKind::Ty(kind); - bound_vars.push(bound_var); - Ty::new_bound( - tcx, - ty::INNERMOST, - ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, - ) - .into() - } - GenericParamDefKind::Lifetime => { - let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); - let bound_var = ty::BoundVariableKind::Region(kind); - bound_vars.push(bound_var); - ty::Region::new_late_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, - ) - .into() - } - GenericParamDefKind::Const { .. } => { - let bound_var = ty::BoundVariableKind::Const; - bound_vars.push(bound_var); - ty::Const::new_bound( - tcx, - ty::INNERMOST, - ty::BoundVar::from_usize(bound_vars.len() - 1), - tcx.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - ) - .into() - } - }, - ); - // When checking something like - // - // trait X { type Y: PartialEq<<Self as X>::Y> } - // impl X for T { default type Y = S; } - // - // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case - // we want <T as X>::Y to normalize to S. This is valid because we are - // checking the default value specifically here. Add this equality to the - // ParamEnv for normalization specifically. - let normalize_impl_ty = tcx.type_of(impl_ty.def_id).instantiate(tcx, normalize_impl_ty_args); - let rebased_args = normalize_impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); - let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars); - let normalize_param_env = { - let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>(); - match normalize_impl_ty.kind() { - ty::Alias(ty::Projection, proj) - if proj.def_id == trait_ty.def_id && proj.args == rebased_args => - { - // Don't include this predicate if the projected type is - // exactly the same as the projection. This can occur in - // (somewhat dubious) code like this: - // - // impl<T> X for T where T: X { type Y = <T as X>::Y; } - } - _ => predicates.push(ty::Clause::from_projection_clause( - tcx, - ty::Binder::bind_with_vars( - ty::ProjectionPredicate { - projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_args), - term: normalize_impl_ty.into(), - }, - bound_vars, - ), - )), - }; - ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing) - }; - debug!(?normalize_param_env); + debug!(?param_env); + let container_id = impl_ty.container_id(tcx); let impl_ty_def_id = impl_ty.def_id.expect_local(); let impl_ty_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id); let rebased_args = impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); @@ -2345,6 +2217,11 @@ pub(super) fn check_type_bounds<'tcx>( .collect(); debug!("check_type_bounds: item_bounds={:?}", obligations); + // Normalize predicates with the assumption that the GAT may always normalize + // to its definition type. This should be the param-env we use to *prove* the + // predicate too, but we don't do that because of performance issues. + // See <https://github.com/rust-lang/rust/pull/117542#issue-1976337685>. + let normalize_param_env = param_env_with_gat_bounds(tcx, impl_ty, impl_trait_ref); for mut obligation in util::elaborate(tcx, obligations) { let normalized_predicate = ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate); @@ -2357,7 +2234,7 @@ pub(super) fn check_type_bounds<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(reported); } @@ -2368,6 +2245,171 @@ pub(super) fn check_type_bounds<'tcx>( ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env) } +/// Install projection predicates that allow GATs to project to their own +/// definition types. This is not allowed in general in cases of default +/// associated types in trait definitions, or when specialization is involved, +/// but is needed when checking these definition types actually satisfy the +/// trait bounds of the GAT. +/// +/// # How it works +/// +/// ```ignore (example) +/// impl<A, B> Foo<u32> for (A, B) { +/// type Bar<C> = Wrapper<A, B, C> +/// } +/// ``` +/// +/// - `impl_trait_ref` would be `<(A, B) as Foo<u32>>` +/// - `normalize_impl_ty_args` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0) +/// - `normalize_impl_ty` would be `Wrapper<A, B, ^0.0>` +/// - `rebased_args` would be `[(A, B), u32, ^0.0]`, combining the args from +/// the *trait* with the generic associated type parameters (as bound vars). +/// +/// A note regarding the use of bound vars here: +/// Imagine as an example +/// ``` +/// trait Family { +/// type Member<C: Eq>; +/// } +/// +/// impl Family for VecFamily { +/// type Member<C: Eq> = i32; +/// } +/// ``` +/// Here, we would generate +/// ```ignore (pseudo-rust) +/// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) } +/// ``` +/// +/// when we really would like to generate +/// ```ignore (pseudo-rust) +/// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) } +/// ``` +/// +/// But, this is probably fine, because although the first clause can be used with types `C` that +/// do not implement `Eq`, for it to cause some kind of problem, there would have to be a +/// `VecFamily::Member<X>` for some type `X` where `!(X: Eq)`, that appears in the value of type +/// `Member<C: Eq> = ....` That type would fail a well-formedness check that we ought to be doing +/// elsewhere, which would check that any `<T as Family>::Member<X>` meets the bounds declared in +/// the trait (notably, that `X: Eq` and `T: Family`). +fn param_env_with_gat_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + impl_ty: ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, +) -> ty::ParamEnv<'tcx> { + let param_env = tcx.param_env(impl_ty.def_id); + let container_id = impl_ty.container_id(tcx); + let mut predicates = param_env.caller_bounds().to_vec(); + + // for RPITITs, we should install predicates that allow us to project all + // of the RPITITs associated with the same body. This is because checking + // the item bounds of RPITITs often involves nested RPITITs having to prove + // bounds about themselves. + let impl_tys_to_install = match impl_ty.opt_rpitit_info { + None => vec![impl_ty], + Some( + ty::ImplTraitInTraitData::Impl { fn_def_id } + | ty::ImplTraitInTraitData::Trait { fn_def_id, .. }, + ) => tcx + .associated_types_for_impl_traits_in_associated_fn(fn_def_id) + .iter() + .map(|def_id| tcx.associated_item(*def_id)) + .collect(), + }; + + for impl_ty in impl_tys_to_install { + let trait_ty = match impl_ty.container { + ty::AssocItemContainer::TraitContainer => impl_ty, + ty::AssocItemContainer::ImplContainer => { + tcx.associated_item(impl_ty.trait_item_def_id.unwrap()) + } + }; + + let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = + smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len()); + // Extend the impl's identity args with late-bound GAT vars + let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id) + .extend_to(tcx, impl_ty.def_id, |param, _| match param.kind { + GenericParamDefKind::Type { .. } => { + let kind = ty::BoundTyKind::Param(param.def_id, param.name); + let bound_var = ty::BoundVariableKind::Ty(kind); + bound_vars.push(bound_var); + Ty::new_bound( + tcx, + ty::INNERMOST, + ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, + ) + .into() + } + GenericParamDefKind::Lifetime => { + let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); + let bound_var = ty::BoundVariableKind::Region(kind); + bound_vars.push(bound_var); + ty::Region::new_late_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind, + }, + ) + .into() + } + GenericParamDefKind::Const { .. } => { + let bound_var = ty::BoundVariableKind::Const; + bound_vars.push(bound_var); + ty::Const::new_bound( + tcx, + ty::INNERMOST, + ty::BoundVar::from_usize(bound_vars.len() - 1), + tcx.type_of(param.def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic"), + ) + .into() + } + }); + // When checking something like + // + // trait X { type Y: PartialEq<<Self as X>::Y> } + // impl X for T { default type Y = S; } + // + // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case + // we want <T as X>::Y to normalize to S. This is valid because we are + // checking the default value specifically here. Add this equality to the + // ParamEnv for normalization specifically. + let normalize_impl_ty = + tcx.type_of(impl_ty.def_id).instantiate(tcx, normalize_impl_ty_args); + let rebased_args = + normalize_impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); + let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars); + + match normalize_impl_ty.kind() { + ty::Alias(ty::Projection, proj) + if proj.def_id == trait_ty.def_id && proj.args == rebased_args => + { + // Don't include this predicate if the projected type is + // exactly the same as the projection. This can occur in + // (somewhat dubious) code like this: + // + // impl<T> X for T where T: X { type Y = <T as X>::Y; } + } + _ => predicates.push( + ty::Binder::bind_with_vars( + ty::ProjectionPredicate { + projection_ty: ty::AliasTy::new(tcx, trait_ty.def_id, rebased_args), + term: normalize_impl_ty.into(), + }, + bound_vars, + ) + .to_predicate(tcx), + ), + }; + } + + ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing) +} + fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str { match impl_item.kind { ty::AssocKind::Const => "const", diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index d9e0e87eb..bc5029a1d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -23,8 +23,12 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( if !tcx.impl_method_has_trait_impl_trait_tys(impl_m.def_id) { return; } - // crate-private traits don't have any library guarantees, there's no need to do this check. - if !tcx.visibility(trait_m.container_id(tcx)).is_public() { + // unreachable traits don't have any library guarantees, there's no need to do this check. + if trait_m + .container_id(tcx) + .as_local() + .is_some_and(|trait_def_id| !tcx.effective_visibilities(()).is_reachable(trait_def_id)) + { return; } diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 3cd3f5bcf..6681292c9 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -158,7 +158,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { ocx.register_bound(cause, param_env, norm_return_ty, term_did); let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors); + infcx.err_ctxt().report_fulfillment_errors(errors); error = true; } // now we can take the return type of the given main function diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 5fa65f33c..15c5558fc 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -90,9 +90,8 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_session::parse::feature_err; -use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::{kw, Ident}; -use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol}; +use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; @@ -114,7 +113,7 @@ pub fn provide(providers: &mut Providers) { region_scope_tree, collect_return_position_impl_trait_in_trait_tys, compare_impl_const: compare_impl_item::compare_impl_const_raw, - check_generator_obligations: check::check_generator_obligations, + check_coroutine_obligations: check::check_coroutine_obligations, ..*providers }; } @@ -588,7 +587,7 @@ pub fn check_function_signature<'tcx>( Ok(()) => { let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors); + infcx.err_ctxt().report_fulfillment_errors(errors); return; } } diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 463fab93e..40b33117f 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -598,7 +598,7 @@ fn resolve_local<'tcx>( } // Make sure we visit the initializer first, so expr_and_pat_count remains correct. - // The correct order, as shared between generator_interior, drop_ranges and intravisitor, + // The correct order, as shared between coroutine_interior, drop_ranges and intravisitor, // is to walk initializer, followed by pattern bindings, finally followed by the `else` block. if let Some(expr) = init { visitor.visit_expr(expr); @@ -825,7 +825,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { resolve_local(self, None, Some(&body.value)); } - if body.generator_kind.is_some() { + if body.coroutine_kind.is_some() { self.scope_tree.body_expr_count.insert(body_id, self.expr_and_pat_count); } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 77614a9a4..eb4491b89 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -93,8 +93,9 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( span: Span, body_def_id: LocalDefId, f: F, -) where - F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>), +) -> Result<(), ErrorGuaranteed> +where + F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>) -> Result<(), ErrorGuaranteed>, { let param_env = tcx.param_env(body_def_id); let infcx = &tcx.infer_ctxt().build(); @@ -105,42 +106,48 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( if !tcx.features().trivial_bounds { wfcx.check_false_global_bounds() } - f(&mut wfcx); + f(&mut wfcx)?; - let assumed_wf_types = match wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id) - { - Ok(wf_types) => wf_types, - Err(_guar) => return, - }; + let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?; let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, assumed_wf_types); let errors = wfcx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors); - return; + let err = infcx.err_ctxt().report_fulfillment_errors(errors); + if tcx.sess.err_count() > 0 { + return Err(err); + } else { + // HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs causes an + // error (delay_span_bug) during normalization, without reporting an error, so we need to act as if + // no error happened, in order to let our callers continue and report an error later in + // check_impl_items_against_trait. + return Ok(()); + } } let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); - let _ = wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env); + wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env)?; + infcx.tainted_by_errors().error_reported() } -fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) { +fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorGuaranteed> { let node = tcx.hir().owner(def_id); - match node { - hir::OwnerNode::Crate(_) => {} + let mut res = match node { + hir::OwnerNode::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"), hir::OwnerNode::Item(item) => check_item(tcx, item), hir::OwnerNode::TraitItem(item) => check_trait_item(tcx, item), hir::OwnerNode::ImplItem(item) => check_impl_item(tcx, item), hir::OwnerNode::ForeignItem(item) => check_foreign_item(tcx, item), - } + }; if let Some(generics) = node.generics() { for param in generics.params { - check_param_wf(tcx, param) + res = res.and(check_param_wf(tcx, param)); } } + res } /// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are @@ -157,7 +164,7 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) { /// not included it frequently leads to confusing errors in fn bodies. So it's better to check /// the types first. #[instrument(skip(tcx), level = "debug")] -fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { +fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<(), ErrorGuaranteed> { let def_id = item.owner_id.def_id; debug!( @@ -187,31 +194,32 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { let is_auto = tcx .impl_trait_ref(def_id) .is_some_and(|trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id)); + let mut res = Ok(()); if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) { let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span); let mut err = tcx.sess.struct_span_err(sp, "impls of auto traits cannot be default"); err.span_labels(impl_.defaultness_span, "default because of this"); err.span_label(sp, "auto trait"); - err.emit(); + res = Err(err.emit()); } // We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span. match (tcx.impl_polarity(def_id), impl_.polarity) { (ty::ImplPolarity::Positive, _) => { - check_impl(tcx, item, impl_.self_ty, &impl_.of_trait); + res = res.and(check_impl(tcx, item, impl_.self_ty, &impl_.of_trait)); } (ty::ImplPolarity::Negative, ast::ImplPolarity::Negative(span)) => { // FIXME(#27579): what amount of WF checking do we need for neg impls? if let hir::Defaultness::Default { .. } = impl_.defaultness { let mut spans = vec![span]; spans.extend(impl_.defaultness_span); - struct_span_err!( + res = Err(struct_span_err!( tcx.sess, spans, E0750, "negative impls cannot be default impls" ) - .emit(); + .emit()); } } (ty::ImplPolarity::Reservation, _) => { @@ -219,49 +227,52 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { } _ => unreachable!(), } + res } hir::ItemKind::Fn(ref sig, ..) => { - check_item_fn(tcx, def_id, item.ident, item.span, sig.decl); + check_item_fn(tcx, def_id, item.ident, item.span, sig.decl) } hir::ItemKind::Static(ty, ..) => { - check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid); + check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid) } hir::ItemKind::Const(ty, ..) => { - check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid); + check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid) } hir::ItemKind::Struct(_, ast_generics) => { - check_type_defn(tcx, item, false); + let res = check_type_defn(tcx, item, false); check_variances_for_type_defn(tcx, item, ast_generics); + res } hir::ItemKind::Union(_, ast_generics) => { - check_type_defn(tcx, item, true); + let res = check_type_defn(tcx, item, true); check_variances_for_type_defn(tcx, item, ast_generics); + res } hir::ItemKind::Enum(_, ast_generics) => { - check_type_defn(tcx, item, true); + let res = check_type_defn(tcx, item, true); check_variances_for_type_defn(tcx, item, ast_generics); + res } - hir::ItemKind::Trait(..) => { - check_trait(tcx, item); - } - hir::ItemKind::TraitAlias(..) => { - check_trait(tcx, item); - } + hir::ItemKind::Trait(..) => check_trait(tcx, item), + hir::ItemKind::TraitAlias(..) => check_trait(tcx, item), // `ForeignItem`s are handled separately. - hir::ItemKind::ForeignMod { .. } => {} + hir::ItemKind::ForeignMod { .. } => Ok(()), hir::ItemKind::TyAlias(hir_ty, ast_generics) => { if tcx.type_alias_is_lazy(item.owner_id) { // Bounds of lazy type aliases and of eager ones that contain opaque types are respected. // E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`. - check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow); + let res = check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow); check_variances_for_type_defn(tcx, item, ast_generics); + res + } else { + Ok(()) } } - _ => {} + _ => Ok(()), } } -fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) { +fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) -> Result<(), ErrorGuaranteed> { let def_id = item.owner_id.def_id; debug!( @@ -276,11 +287,14 @@ fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) { hir::ForeignItemKind::Static(ty, ..) => { check_item_type(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail) } - hir::ForeignItemKind::Type => (), + hir::ForeignItemKind::Type => Ok(()), } } -fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) { +fn check_trait_item( + tcx: TyCtxt<'_>, + trait_item: &hir::TraitItem<'_>, +) -> Result<(), ErrorGuaranteed> { let def_id = trait_item.owner_id.def_id; let (method_sig, span) = match trait_item.kind { @@ -289,18 +303,19 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) { _ => (None, trait_item.span), }; check_object_unsafe_self_trait_by_name(tcx, trait_item); - check_associated_item(tcx, def_id, span, method_sig); + let mut res = check_associated_item(tcx, def_id, span, method_sig); if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) { for &assoc_ty_def_id in tcx.associated_types_for_impl_traits_in_associated_fn(def_id) { - check_associated_item( + res = res.and(check_associated_item( tcx, assoc_ty_def_id.expect_local(), tcx.def_span(assoc_ty_def_id), None, - ); + )); } } + res } /// Require that the user writes where clauses on GATs for the implicit @@ -315,9 +330,10 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) { /// fn into_iter<'a>(&'a self) -> Self::Iter<'a>; /// } /// ``` -fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRef]) { +fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { // Associates every GAT's def_id to a list of possibly missing bounds detected by this lint. let mut required_bounds_by_item = FxHashMap::default(); + let associated_items = tcx.associated_items(trait_def_id); // Loop over all GATs together, because if this lint suggests adding a where-clause bound // to one GAT, it might then require us to an additional bound on another GAT. @@ -326,8 +342,8 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe // those GATs. loop { let mut should_continue = false; - for gat_item in associated_items { - let gat_def_id = gat_item.id.owner_id; + for gat_item in associated_items.in_definition_order() { + let gat_def_id = gat_item.def_id.expect_local(); let gat_item = tcx.associated_item(gat_def_id); // If this item is not an assoc ty, or has no args, then it's not a GAT if gat_item.kind != ty::AssocKind::Type { @@ -343,8 +359,8 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe // This is calculated by taking the intersection of the bounds that each item // constrains the GAT with individually. let mut new_required_bounds: Option<FxHashSet<ty::Clause<'_>>> = None; - for item in associated_items { - let item_def_id = item.id.owner_id; + for item in associated_items.in_definition_order() { + let item_def_id = item.def_id.expect_local(); // Skip our own GAT, since it does not constrain itself at all. if item_def_id == gat_def_id { continue; @@ -352,9 +368,9 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe let param_env = tcx.param_env(item_def_id); - let item_required_bounds = match item.kind { + let item_required_bounds = match tcx.associated_item(item_def_id).kind { // In our example, this corresponds to `into_iter` method - hir::AssocItemKind::Fn { .. } => { + ty::AssocKind::Fn => { // For methods, we check the function signature's return type for any GATs // to constrain. In the `into_iter` case, we see that the return type // `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from. @@ -370,12 +386,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe // We also assume that all of the function signature's parameter types // are well formed. &sig.inputs().iter().copied().collect(), - gat_def_id.def_id, + gat_def_id, gat_generics, ) } // In our example, this corresponds to the `Iter` and `Item` associated types - hir::AssocItemKind::Type => { + ty::AssocKind::Type => { // If our associated item is a GAT with missing bounds, add them to // the param-env here. This allows this GAT to propagate missing bounds // to other GATs. @@ -392,11 +408,11 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe .instantiate_identity_iter_copied() .collect::<Vec<_>>(), &FxIndexSet::default(), - gat_def_id.def_id, + gat_def_id, gat_generics, ) } - hir::AssocItemKind::Const => None, + ty::AssocKind::Const => None, }; if let Some(item_required_bounds) = item_required_bounds { @@ -432,7 +448,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe } for (gat_def_id, required_bounds) in required_bounds_by_item { - let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id.def_id); + // Don't suggest adding `Self: 'a` to a GAT that can't be named + if tcx.is_impl_trait_in_trait(gat_def_id.to_def_id()) { + continue; + } + + let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id); debug!(?required_bounds); let param_env = tcx.param_env(gat_def_id); @@ -442,21 +463,16 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => { !region_known_to_outlive( tcx, - gat_def_id.def_id, + gat_def_id, param_env, &FxIndexSet::default(), a, b, ) } - ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => !ty_known_to_outlive( - tcx, - gat_def_id.def_id, - param_env, - &FxIndexSet::default(), - a, - b, - ), + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => { + !ty_known_to_outlive(tcx, gat_def_id, param_env, &FxIndexSet::default(), a, b) + } _ => bug!("Unexpected ClauseKind"), }) .map(|clause| clause.to_string()) @@ -535,7 +551,7 @@ fn augment_param_env<'tcx>( fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - item_def_id: hir::OwnerId, + item_def_id: LocalDefId, to_check: T, wf_tys: &FxIndexSet<Ty<'tcx>>, gat_def_id: LocalDefId, @@ -568,7 +584,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( // reflected in a where clause on the GAT itself. for (ty, ty_idx) in &types { // In our example, requires that `Self: 'a` - if ty_known_to_outlive(tcx, item_def_id.def_id, param_env, &wf_tys, *ty, *region_a) { + if ty_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *ty, *region_a) { debug!(?ty_idx, ?region_a_idx); debug!("required clause: {ty} must outlive {region_a}"); // Translate into the generic parameters of the GAT. In @@ -607,14 +623,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( if matches!(**region_b, ty::ReStatic | ty::ReError(_)) || region_a == region_b { continue; } - if region_known_to_outlive( - tcx, - item_def_id.def_id, - param_env, - &wf_tys, - *region_a, - *region_b, - ) { + if region_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *region_a, *region_b) { debug!(?region_a_idx, ?region_b_idx); debug!("required clause: {region_a} must outlive {region_b}"); // Translate into the generic parameters of the GAT. @@ -833,7 +842,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem } } -fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) { +fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) -> Result<(), ErrorGuaranteed> { let (method_sig, span) = match impl_item.kind { hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span), // Constrain binding and overflow error spans to `<Ty>` in `type foo = <Ty>`. @@ -841,13 +850,13 @@ fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) { _ => (None, impl_item.span), }; - check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig); + check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig) } -fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { +fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ErrorGuaranteed> { match param.kind { // We currently only check wf of const params here. - hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => (), + hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => Ok(()), // Const parameters are well formed if their type is structural match. hir::GenericParamKind::Const { ty: hir_ty, default: _ } => { @@ -867,68 +876,67 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { ty, trait_def_id, ); - }); + Ok(()) + }) } else { - let diag = match ty.kind() { - ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None, - ty::FnPtr(_) => Some(tcx.sess.struct_span_err( + let mut diag = match ty.kind() { + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => return Ok(()), + ty::FnPtr(_) => tcx.sess.struct_span_err( hir_ty.span, "using function pointers as const generic parameters is forbidden", - )), - ty::RawPtr(_) => Some(tcx.sess.struct_span_err( + ), + ty::RawPtr(_) => tcx.sess.struct_span_err( hir_ty.span, "using raw pointers as const generic parameters is forbidden", - )), - _ => Some(tcx.sess.struct_span_err( + ), + _ => tcx.sess.struct_span_err( hir_ty.span, format!("`{}` is forbidden as the type of a const generic parameter", ty), - )), + ), }; - if let Some(mut diag) = diag { - diag.note("the only supported types are integers, `bool` and `char`"); + diag.note("the only supported types are integers, `bool` and `char`"); - let cause = ObligationCause::misc(hir_ty.span, param.def_id); - let may_suggest_feature = match type_allowed_to_implement_const_param_ty( - tcx, - tcx.param_env(param.def_id), - ty, - cause, - ) { - // Can never implement `ConstParamTy`, don't suggest anything. - Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => false, - // May be able to implement `ConstParamTy`. Only emit the feature help - // if the type is local, since the user may be able to fix the local type. - Err(ConstParamTyImplementationError::InfrigingFields(..)) => { - fn ty_is_local(ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Adt(adt_def, ..) => adt_def.did().is_local(), - // Arrays and slices use the inner type's `ConstParamTy`. - ty::Array(ty, ..) => ty_is_local(*ty), - ty::Slice(ty) => ty_is_local(*ty), - // `&` references use the inner type's `ConstParamTy`. - // `&mut` are not supported. - ty::Ref(_, ty, ast::Mutability::Not) => ty_is_local(*ty), - // Say that a tuple is local if any of its components are local. - // This is not strictly correct, but it's likely that the user can fix the local component. - ty::Tuple(tys) => tys.iter().any(|ty| ty_is_local(ty)), - _ => false, - } + let cause = ObligationCause::misc(hir_ty.span, param.def_id); + let may_suggest_feature = match type_allowed_to_implement_const_param_ty( + tcx, + tcx.param_env(param.def_id), + ty, + cause, + ) { + // Can never implement `ConstParamTy`, don't suggest anything. + Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => false, + // May be able to implement `ConstParamTy`. Only emit the feature help + // if the type is local, since the user may be able to fix the local type. + Err(ConstParamTyImplementationError::InfrigingFields(..)) => { + fn ty_is_local(ty: Ty<'_>) -> bool { + match ty.kind() { + ty::Adt(adt_def, ..) => adt_def.did().is_local(), + // Arrays and slices use the inner type's `ConstParamTy`. + ty::Array(ty, ..) => ty_is_local(*ty), + ty::Slice(ty) => ty_is_local(*ty), + // `&` references use the inner type's `ConstParamTy`. + // `&mut` are not supported. + ty::Ref(_, ty, ast::Mutability::Not) => ty_is_local(*ty), + // Say that a tuple is local if any of its components are local. + // This is not strictly correct, but it's likely that the user can fix the local component. + ty::Tuple(tys) => tys.iter().any(|ty| ty_is_local(ty)), + _ => false, } - - ty_is_local(ty) } - // Implments `ConstParamTy`, suggest adding the feature to enable. - Ok(..) => true, - }; - if may_suggest_feature && tcx.sess.is_nightly_build() { - diag.help( + + ty_is_local(ty) + } + // Implments `ConstParamTy`, suggest adding the feature to enable. + Ok(..) => true, + }; + if may_suggest_feature && tcx.sess.is_nightly_build() { + diag.help( "add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types", ); - } - - diag.emit(); } + + Err(diag.emit()) } } } @@ -940,7 +948,7 @@ fn check_associated_item( item_id: LocalDefId, span: Span, sig_if_method: Option<&hir::FnSig<'_>>, -) { +) -> Result<(), ErrorGuaranteed> { let loc = Some(WellFormedLoc::Ty(item_id)); enter_wf_checking_ctxt(tcx, span, item_id, |wfcx| { let item = tcx.associated_item(item_id); @@ -955,6 +963,7 @@ fn check_associated_item( let ty = tcx.type_of(item.def_id).instantiate_identity(); let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); wfcx.register_wf_obligation(span, loc, ty.into()); + Ok(()) } ty::AssocKind::Fn => { let sig = tcx.fn_sig(item.def_id).instantiate_identity(); @@ -966,7 +975,7 @@ fn check_associated_item( hir_sig.decl, item.def_id.expect_local(), ); - check_method_receiver(wfcx, hir_sig, item, self_ty); + check_method_receiver(wfcx, hir_sig, item, self_ty) } ty::AssocKind::Type => { if let ty::AssocItemContainer::TraitContainer = item.container { @@ -977,6 +986,7 @@ fn check_associated_item( let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); wfcx.register_wf_obligation(span, loc, ty.into()); } + Ok(()) } } }) @@ -992,7 +1002,11 @@ fn item_adt_kind(kind: &ItemKind<'_>) -> Option<AdtKind> { } /// In a type definition, we check that to ensure that the types of the fields are well-formed. -fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: bool) { +fn check_type_defn<'tcx>( + tcx: TyCtxt<'tcx>, + item: &hir::Item<'tcx>, + all_sized: bool, +) -> Result<(), ErrorGuaranteed> { let _ = tcx.representability(item.owner_id.def_id); let adt_def = tcx.adt_def(item.owner_id); @@ -1087,11 +1101,12 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b } check_where_clauses(wfcx, item.span, item.owner_id.def_id); - }); + Ok(()) + }) } #[instrument(skip(tcx, item))] -fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { +fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) -> Result<(), ErrorGuaranteed> { debug!(?item.owner_id); let def_id = item.owner_id.def_id; @@ -1110,14 +1125,16 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { } } - enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| { - check_where_clauses(wfcx, item.span, def_id) + let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| { + check_where_clauses(wfcx, item.span, def_id); + Ok(()) }); // Only check traits, don't check trait aliases - if let hir::ItemKind::Trait(_, _, _, _, items) = item.kind { - check_gat_where_clauses(tcx, items); + if let hir::ItemKind::Trait(..) = item.kind { + check_gat_where_clauses(tcx, item.owner_id.def_id); } + res } /// Checks all associated type defaults of trait `trait_def_id`. @@ -1131,11 +1148,11 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt let wf_obligations = bounds.instantiate_identity_iter_copied().flat_map(|(bound, bound_span)| { let normalized_bound = wfcx.normalize(span, None, bound); - traits::wf::predicate_obligations( + traits::wf::clause_obligations( wfcx.infcx, wfcx.param_env, wfcx.body_def_id, - normalized_bound.as_predicate(), + normalized_bound, bound_span, ) }); @@ -1149,10 +1166,11 @@ fn check_item_fn( ident: Ident, span: Span, decl: &hir::FnDecl<'_>, -) { +) -> Result<(), ErrorGuaranteed> { enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| { let sig = tcx.fn_sig(def_id).instantiate_identity(); check_fn_or_method(wfcx, ident.span, sig, decl, def_id); + Ok(()) }) } @@ -1167,7 +1185,7 @@ fn check_item_type( item_id: LocalDefId, ty_span: Span, unsized_handling: UnsizedHandling, -) { +) -> Result<(), ErrorGuaranteed> { debug!("check_item_type: {:?}", item_id); enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| { @@ -1207,7 +1225,8 @@ fn check_item_type( tcx.require_lang_item(LangItem::Sync, Some(ty_span)), ); } - }); + Ok(()) + }) } #[instrument(level = "debug", skip(tcx, ast_self_ty, ast_trait_ref))] @@ -1216,7 +1235,7 @@ fn check_impl<'tcx>( item: &'tcx hir::Item<'tcx>, ast_self_ty: &hir::Ty<'_>, ast_trait_ref: &Option<hir::TraitRef<'_>>, -) { +) -> Result<(), ErrorGuaranteed> { enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| { match ast_trait_ref { Some(ast_trait_ref) => { @@ -1235,7 +1254,7 @@ fn check_impl<'tcx>( wfcx.infcx, wfcx.param_env, wfcx.body_def_id, - &trait_pred, + trait_pred, ast_trait_ref.path.span, item, ); @@ -1265,7 +1284,8 @@ fn check_impl<'tcx>( } check_where_clauses(wfcx, item.span, item.owner_id.def_id); - }); + Ok(()) + }) } /// Checks where-clauses and inline bounds that are declared on `def_id`. @@ -1444,13 +1464,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id debug!(?predicates.predicates); assert_eq!(predicates.predicates.len(), predicates.spans.len()); let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| { - traits::wf::predicate_obligations( - infcx, - wfcx.param_env, - wfcx.body_def_id, - p.as_predicate(), - sp, - ) + traits::wf::clause_obligations(infcx, wfcx.param_env, wfcx.body_def_id, p, sp) }); let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect(); wfcx.register_obligations(obligations); @@ -1543,11 +1557,11 @@ fn check_method_receiver<'tcx>( fn_sig: &hir::FnSig<'_>, method: ty::AssocItem, self_ty: Ty<'tcx>, -) { +) -> Result<(), ErrorGuaranteed> { let tcx = wfcx.tcx(); if !method.fn_has_self_parameter { - return; + return Ok(()); } let span = fn_sig.decl.inputs[0].span; @@ -1566,11 +1580,11 @@ fn check_method_receiver<'tcx>( if tcx.features().arbitrary_self_types { if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) { // Report error; `arbitrary_self_types` was enabled. - e0307(tcx, span, receiver_ty); + return Err(e0307(tcx, span, receiver_ty)); } } else { if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, false) { - if receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) { + return Err(if receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) { // Report error; would have worked with `arbitrary_self_types`. feature_err( &tcx.sess.parse_sess, @@ -1582,16 +1596,17 @@ fn check_method_receiver<'tcx>( ), ) .help(HELP_FOR_SELF_TYPE) - .emit(); + .emit() } else { // Report error; would not have worked with `arbitrary_self_types`. - e0307(tcx, span, receiver_ty); - } + e0307(tcx, span, receiver_ty) + }); } } + Ok(()) } -fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) { +fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) -> ErrorGuaranteed { struct_span_err!( tcx.sess.diagnostic(), span, @@ -1600,7 +1615,7 @@ fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) { ) .note("type of `self` must be `Self` or a type that dereferences to it") .help(HELP_FOR_SELF_TYPE) - .emit(); + .emit() } /// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If @@ -1892,12 +1907,12 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { } } -fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) { +fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> { let items = tcx.hir_module_items(module); - items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id)); - items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id)); - items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id)); - items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id)); + let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id)); + res = res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id))); + res = res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id))); + res.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id))) } fn error_392( |