summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/check
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /compiler/rustc_hir_analysis/src/check
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-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.rs101
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs342
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/entry.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs339
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(