diff options
| author | Trevor Gross <t.gross35@gmail.com> | 2025-06-18 20:22:48 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-06-18 20:22:48 -0400 |
| commit | cff8e9ae142c3dcaf4c66ec5b6be932f1442c4b5 (patch) | |
| tree | f3a817601e97ce7acaaedf8d983c7811fc03b8ca | |
| parent | 044514eb26511d2d8aa999fdf27e85df6beb6576 (diff) | |
| parent | 377d8fa4e3057838f20dd1eb1669d4ebaf8a561a (diff) | |
| download | rust-cff8e9ae142c3dcaf4c66ec5b6be932f1442c4b5.tar.gz rust-cff8e9ae142c3dcaf4c66ec5b6be932f1442c4b5.zip | |
Rollup merge of #140247 - BoxyUwU:iats_no_query_cycles, r=lcnr
Don't build `ParamEnv` and do trait solving in `ItemCtxt`s when lowering IATs Fixes rust-lang/rust#108491 Fixes rust-lang/rust#125879 This was due to updating inhabited predicate stuff which I had to do to make constructing ADTs with IATs in fields not ICE Fixes rust-lang/rust#136678 (but no test added, I don't rly care about weird IAT edge cases under GCE) Fixes rust-lang/rust#138131 Avoids doing "fully correct" candidate selection for IATs during hir ty lowering when in item signatures as it almost always leads to a query cycle from trying to build a `ParamEnv`. I replaced it with a use `DeepRejectCtxt` which should be able to handle this kind of conservative "could these types unify" while in a context where we don't want to do type equality. This is a relatively simple scheme and should be forwards compatible with doing something more complex/powerful. I'm not really sure how this interacts with rust-lang/rust#126651, though I'm also not really sure its super important to support projecting IATs from IAT self types given we don't even support `T::Assoc::Other` for trait-associated types so didn't give much thought to how this might fit in with that. r? `@compiler-errors` cc `@fmease`
31 files changed, 542 insertions, 288 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 6e22ac5a28a..176d955bf03 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -34,16 +34,22 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause}; use rustc_middle::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode, fold_regions}; +use rustc_middle::ty::{ + self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, TypingMode, fold_regions, +}; use rustc_middle::{bug, span_bug}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_trait_selection::traits::{ObligationCtxt, hir_ty_lowering_dyn_compatibility_violations}; +use rustc_trait_selection::traits::{ + FulfillmentError, ObligationCtxt, hir_ty_lowering_dyn_compatibility_violations, +}; use tracing::{debug, instrument}; use crate::errors; -use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason}; +use crate::hir_ty_lowering::{ + FeedConstTy, HirTyLowerer, InherentAssocCandidate, RegionInferReason, +}; pub(crate) mod dump; mod generics_of; @@ -364,6 +370,58 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_ident)) } + #[instrument(level = "debug", skip(self, _span), ret)] + fn select_inherent_assoc_candidates( + &self, + _span: Span, + self_ty: Ty<'tcx>, + candidates: Vec<InherentAssocCandidate>, + ) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>) { + assert!(!self_ty.has_infer()); + + // We don't just call the normal normalization routine here as we can't provide the + // correct `ParamEnv` and it would be wrong to invoke arbitrary trait solving under + // the wrong `ParamEnv`. Expanding free aliases doesn't need a `ParamEnv` so we do + // this just to make resolution a little bit smarter. + let self_ty = self.tcx.expand_free_alias_tys(self_ty); + debug!("select_inherent_assoc_candidates: self_ty={:?}", self_ty); + + let candidates = candidates + .into_iter() + .filter(|&InherentAssocCandidate { impl_, .. }| { + let impl_ty = self.tcx().type_of(impl_).instantiate_identity(); + + // See comment on doing this operation for `self_ty` + let impl_ty = self.tcx.expand_free_alias_tys(impl_ty); + debug!("select_inherent_assoc_candidates: impl_ty={:?}", impl_ty); + + // We treat parameters in the self ty as rigid and parameters in the impl ty as infers + // because it allows `impl<T> Foo<T>` to unify with `Foo<u8>::IAT`, while also disallowing + // `Foo<T>::IAT` from unifying with `impl Foo<u8>`. + // + // We don't really care about a depth limit here because we're only working with user-written + // types and if they wrote a type that would take hours to walk then that's kind of on them. On + // the other hand the default depth limit is relatively low and could realistically be hit by + // users in normal cases. + // + // `DeepRejectCtxt` leads to slightly worse IAT resolution than real type equality in cases + // where the `impl_ty` has repeated uses of generic parameters. E.g. `impl<T> Foo<T, T>` would + // be considered a valid candidate when resolving `Foo<u8, u16>::IAT`. + // + // Not replacing escaping bound vars in `self_ty` with placeholders also leads to slightly worse + // resolution, but it probably won't come up in practice and it would be backwards compatible + // to switch over to doing that. + ty::DeepRejectCtxt::relate_rigid_infer(self.tcx).types_may_unify_with_depth( + self_ty, + impl_ty, + usize::MAX, + ) + }) + .collect(); + + (candidates, vec![]) + } + fn lower_assoc_item_path( &self, span: Span, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 1cda6dff21e..0e79a8918b0 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -26,6 +26,7 @@ use rustc_trait_selection::traits::{ use smallvec::SmallVec; use tracing::debug; +use super::InherentAssocCandidate; use crate::errors::{ self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams, ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits, @@ -793,7 +794,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, name: Ident, self_ty: Ty<'tcx>, - candidates: Vec<(DefId, (DefId, DefId))>, + candidates: Vec<InherentAssocCandidate>, fulfillment_errors: Vec<FulfillmentError<'tcx>>, span: Span, assoc_tag: ty::AssocTag, @@ -827,8 +828,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let type_candidates = candidates .iter() .take(limit) - .map(|&(impl_, _)| { - format!("- `{}`", tcx.at(span).type_of(impl_).instantiate_identity()) + .map(|cand| { + format!("- `{}`", tcx.at(span).type_of(cand.impl_).instantiate_identity()) }) .collect::<Vec<_>>() .join("\n"); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index bf407cbaccb..b99f7b44661 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -33,13 +33,14 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause}; +use rustc_infer::traits::DynCompatibilityViolation; +use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ - self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt, - TypeVisitableExt, TypingMode, Upcast, fold_regions, + self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, + TypingMode, Upcast, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; @@ -47,7 +48,7 @@ use rustc_session::parse::feature_err; use rustc_span::{DUMMY_SP, Ident, Span, kw, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; -use rustc_trait_selection::traits::{self, ObligationCtxt}; +use rustc_trait_selection::traits::{self, FulfillmentError}; use tracing::{debug, instrument}; use crate::check::check_abi_fn_ptr; @@ -99,6 +100,13 @@ pub enum RegionInferReason<'a> { OutlivesBound, } +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Debug)] +pub struct InherentAssocCandidate { + pub impl_: DefId, + pub assoc_item: DefId, + pub scope: DefId, +} + /// A context which can lower type-system entities from the [HIR][hir] to /// the [`rustc_middle::ty`] representation. /// @@ -148,6 +156,13 @@ pub trait HirTyLowerer<'tcx> { assoc_ident: Ident, ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]>; + fn select_inherent_assoc_candidates( + &self, + span: Span, + self_ty: Ty<'tcx>, + candidates: Vec<InherentAssocCandidate>, + ) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>); + /// Lower a path to an associated item (of a trait) to a projection. /// /// This method has to be defined by the concrete lowering context because @@ -1449,48 +1464,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .filter_map(|&impl_| { let (item, scope) = self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?; - Some((impl_, (item.def_id, scope))) + Some(InherentAssocCandidate { impl_, assoc_item: item.def_id, scope }) }) .collect(); - if candidates.is_empty() { - return Ok(None); - } - - // - // Select applicable inherent associated type candidates modulo regions. - // - - // In contexts that have no inference context, just make a new one. - // We do need a local variable to store it, though. - let infcx = match self.infcx() { - Some(infcx) => infcx, - None => { - assert!(!self_ty.has_infer()); - &tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()) - } - }; + let (applicable_candidates, fulfillment_errors) = + self.select_inherent_assoc_candidates(span, self_ty, candidates.clone()); - // FIXME(inherent_associated_types): Acquiring the ParamEnv this early leads to cycle errors - // when inside of an ADT (#108491) or where clause. - let param_env = tcx.param_env(block.owner); + let InherentAssocCandidate { impl_, assoc_item, scope: def_scope } = + match &applicable_candidates[..] { + &[] => Err(self.report_unresolved_inherent_assoc_item( + name, + self_ty, + candidates, + fulfillment_errors, + span, + assoc_tag, + )), - let mut universes = if self_ty.has_escaping_bound_vars() { - vec![None; self_ty.outer_exclusive_binder().as_usize()] - } else { - vec![] - }; + &[applicable_candidate] => Ok(applicable_candidate), - let (impl_, (assoc_item, def_scope)) = crate::traits::with_replaced_escaping_bound_vars( - infcx, - &mut universes, - self_ty, - |self_ty| { - self.select_inherent_assoc_candidates( - infcx, name, span, self_ty, param_env, candidates, assoc_tag, - ) - }, - )?; + &[_, ..] => Err(self.report_ambiguous_inherent_assoc_item( + name, + candidates.into_iter().map(|cand| cand.assoc_item).collect(), + span, + )), + }?; self.check_assoc_item(assoc_item, name, def_scope, block, span); @@ -1507,78 +1506,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ok(Some((assoc_item, args))) } - fn select_inherent_assoc_candidates( - &self, - infcx: &InferCtxt<'tcx>, - name: Ident, - span: Span, - self_ty: Ty<'tcx>, - param_env: ParamEnv<'tcx>, - candidates: Vec<(DefId, (DefId, DefId))>, - assoc_tag: ty::AssocTag, - ) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> { - let tcx = self.tcx(); - let mut fulfillment_errors = Vec::new(); - - let applicable_candidates: Vec<_> = candidates - .iter() - .copied() - .filter(|&(impl_, _)| { - infcx.probe(|_| { - let ocx = ObligationCtxt::new_with_diagnostics(infcx); - let self_ty = ocx.normalize(&ObligationCause::dummy(), param_env, self_ty); - - let impl_args = infcx.fresh_args_for_item(span, impl_); - let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args); - let impl_ty = ocx.normalize(&ObligationCause::dummy(), param_env, impl_ty); - - // Check that the self types can be related. - if ocx.eq(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err() { - return false; - } - - // Check whether the impl imposes obligations we have to worry about. - let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args); - let impl_bounds = - ocx.normalize(&ObligationCause::dummy(), param_env, impl_bounds); - let impl_obligations = traits::predicates_for_generics( - |_, _| ObligationCause::dummy(), - param_env, - impl_bounds, - ); - ocx.register_obligations(impl_obligations); - - let mut errors = ocx.select_where_possible(); - if !errors.is_empty() { - fulfillment_errors.append(&mut errors); - return false; - } - - true - }) - }) - .collect(); - - match &applicable_candidates[..] { - &[] => Err(self.report_unresolved_inherent_assoc_item( - name, - self_ty, - candidates, - fulfillment_errors, - span, - assoc_tag, - )), - - &[applicable_candidate] => Ok(applicable_candidate), - - &[_, ..] => Err(self.report_ambiguous_inherent_assoc_item( - name, - applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(), - span, - )), - } - } - /// Given name and kind search for the assoc item in the provided scope and check if it's accessible[^1]. /// /// [^1]: I.e., accessible in the provided scope wrt. visibility and stability. diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index e979798a402..8c18642e54a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -12,7 +12,9 @@ use hir::def_id::CRATE_DEF_ID; use rustc_errors::DiagCtxtHandle; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, HirId, ItemLocalMap}; -use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; +use rustc_hir_analysis::hir_ty_lowering::{ + HirTyLowerer, InherentAssocCandidate, RegionInferReason, +}; use rustc_infer::infer; use rustc_infer::traits::{DynCompatibilityViolation, Obligation}; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; @@ -20,7 +22,9 @@ use rustc_session::Session; use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym}; use rustc_trait_selection::error_reporting::TypeErrCtxt; use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations; -use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; +use rustc_trait_selection::traits::{ + self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, +}; use crate::coercion::DynamicCoerceMany; use crate::fallback::DivergingFallbackBehavior; @@ -310,6 +314,67 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { )) } + fn select_inherent_assoc_candidates( + &self, + span: Span, + self_ty: Ty<'tcx>, + candidates: Vec<InherentAssocCandidate>, + ) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>) { + let tcx = self.tcx(); + let infcx = &self.infcx; + let mut fulfillment_errors = vec![]; + + let mut filter_iat_candidate = |self_ty, impl_| { + let ocx = ObligationCtxt::new_with_diagnostics(self); + let self_ty = ocx.normalize(&ObligationCause::dummy(), self.param_env, self_ty); + + let impl_args = infcx.fresh_args_for_item(span, impl_); + let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args); + let impl_ty = ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_ty); + + // Check that the self types can be related. + if ocx.eq(&ObligationCause::dummy(), self.param_env, impl_ty, self_ty).is_err() { + return false; + } + + // Check whether the impl imposes obligations we have to worry about. + let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args); + let impl_bounds = ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_bounds); + let impl_obligations = traits::predicates_for_generics( + |_, _| ObligationCause::dummy(), + self.param_env, + impl_bounds, + ); + ocx.register_obligations(impl_obligations); + + let mut errors = ocx.select_where_possible(); + if !errors.is_empty() { + fulfillment_errors.append(&mut errors); + return false; + } + + true + }; + + let mut universes = if self_ty.has_escaping_bound_vars() { + vec![None; self_ty.outer_exclusive_binder().as_usize()] + } else { + vec![] + }; + + let candidates = + traits::with_replaced_escaping_bound_vars(infcx, &mut universes, self_ty, |self_ty| { + candidates + .into_iter() + .filter(|&InherentAssocCandidate { impl_, .. }| { + infcx.probe(|_| filter_iat_candidate(self_ty, impl_)) + }) + .collect() + }); + + (candidates, fulfillment_errors) + } + fn lower_assoc_item_path( &self, span: Span, diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index d8bab58545f..2a336cc21f4 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -127,7 +127,9 @@ impl<'tcx> Ty<'tcx> { InhabitedPredicate::True } Never => InhabitedPredicate::False, - Param(_) | Alias(ty::Projection | ty::Free, _) => InhabitedPredicate::GenericType(self), + Param(_) | Alias(ty::Inherent | ty::Projection | ty::Free, _) => { + InhabitedPredicate::GenericType(self) + } Alias(ty::Opaque, alias_ty) => { match alias_ty.def_id.as_local() { // Foreign opaque is considered inhabited. @@ -139,12 +141,6 @@ impl<'tcx> Ty<'tcx> { } } } - // FIXME(inherent_associated_types): Most likely we can just map to `GenericType` like above. - // However it's unclear if the args passed to `InhabitedPredicate::instantiate` are of the correct - // format, i.e. don't contain parent args. If you hit this case, please verify this beforehand. - Alias(ty::Inherent, _) => { - bug!("unimplemented: inhabitedness checking for inherent projections") - } Tuple(tys) if tys.is_empty() => InhabitedPredicate::True, // use a query for more complex cases Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self), diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index fa5e8d43702..d88c88fc6f3 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -240,6 +240,10 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_ self.types_may_unify_inner(lhs, rhs, Self::STARTING_DEPTH) } + pub fn types_may_unify_with_depth(self, lhs: I::Ty, rhs: I::Ty, depth_limit: usize) -> bool { + self.types_may_unify_inner(lhs, rhs, depth_limit) + } + fn args_may_unify_inner( self, obligation_args: I::GenericArgs, diff --git a/tests/crashes/136678.rs b/tests/crashes/136678.rs deleted file mode 100644 index e7d7de23bfe..00000000000 --- a/tests/crashes/136678.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ known-bug: #136678 -#![feature(inherent_associated_types)] -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] - -struct B<const A: usize>; - -struct Test<const A: usize>; - -impl<const A: usize> Test<A> { - type B = B<{ A }>; - - fn test(a: Self::B) -> Self::B { - a - } -} - -pub fn main() {} diff --git a/tests/crashes/138131.rs b/tests/crashes/138131.rs deleted file mode 100644 index f400c02de8d..00000000000 --- a/tests/crashes/138131.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #138131 -#![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] -struct Foo<'a> { - x: &'a (), -} - -impl<'a> Foo<'a> { - fn foo(_: [u8; Foo::X]) {} -} - -fn main() {} diff --git a/tests/ui/associated-inherent-types/bound_vars_in_args.rs b/tests/ui/associated-inherent-types/bound_vars_in_args.rs new file mode 100644 index 00000000000..49a9ef31cd6 --- /dev/null +++ b/tests/ui/associated-inherent-types/bound_vars_in_args.rs @@ -0,0 +1,22 @@ +#![feature(non_lifetime_binders, inherent_associated_types)] +#![expect(incomplete_features)] + +// Test whether we can resolve to the right IAT when the self type +// contains a bound type. This should ideally use the second impl. + +struct Foo<T: ?Sized>(T); + +impl Foo<[u8]> { + type IAT = u8; +} + +impl<T: Sized> Foo<T> { + type IAT = u8; +} + +struct Bar +where + for<T> Foo<T>::IAT: Sized; + //~^ ERROR: multiple applicable items in scope + +fn main() {} diff --git a/tests/ui/associated-inherent-types/bound_vars_in_args.stderr b/tests/ui/associated-inherent-types/bound_vars_in_args.stderr new file mode 100644 index 00000000000..9e880476f6a --- /dev/null +++ b/tests/ui/associated-inherent-types/bound_vars_in_args.stderr @@ -0,0 +1,20 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/bound_vars_in_args.rs:19:20 + | +LL | for<T> Foo<T>::IAT: Sized; + | ^^^ multiple `IAT` found + | +note: candidate #1 is defined in an impl for the type `Foo<[u8]>` + --> $DIR/bound_vars_in_args.rs:10:5 + | +LL | type IAT = u8; + | ^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Foo<T>` + --> $DIR/bound_vars_in_args.rs:14:5 + | +LL | type IAT = u8; + | ^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr deleted file mode 100644 index 7f8ed898525..00000000000 --- a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0391]: cycle detected when computing predicates of `Foo` - --> $DIR/cycle-iat-inside-of-adt.rs:7:1 - | -LL | struct Foo { - | ^^^^^^^^^^ - | -note: ...which requires computing inferred outlives-predicates of `Foo`... - --> $DIR/cycle-iat-inside-of-adt.rs:7:1 - | -LL | struct Foo { - | ^^^^^^^^^^ - = note: ...which requires computing the inferred outlives-predicates for items in this crate... -note: ...which requires computing type of `Foo::bar`... - --> $DIR/cycle-iat-inside-of-adt.rs:8:5 - | -LL | bar: Self::Bar, - | ^^^^^^^^^^^^^^ -note: ...which requires computing normalized predicates of `Foo`... - --> $DIR/cycle-iat-inside-of-adt.rs:7:1 - | -LL | struct Foo { - | ^^^^^^^^^^ - = note: ...which again requires computing predicates of `Foo`, completing the cycle -note: cycle used when checking that `Foo` is well-formed - --> $DIR/cycle-iat-inside-of-adt.rs:7:1 - | -LL | struct Foo { - | ^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.rs b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.rs deleted file mode 100644 index 902094b9862..00000000000 --- a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: unknown - -#![feature(inherent_associated_types)] -#![allow(incomplete_features)] - -// FIXME(inherent_associated_types): This shouldn't lead to a cycle error. - -fn user<T>() where S<T>::P: std::fmt::Debug {} - -struct S<T>; - -impl<T: Copy> S<T> { - type P = (); -} - -fn main() {} diff --git a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.stderr b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.stderr deleted file mode 100644 index e97a5df9d49..00000000000 --- a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error[E0391]: cycle detected when computing predicates of `user` - --> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1 - | -LL | fn user<T>() where S<T>::P: std::fmt::Debug {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires computing explicit predicates of `user`... - --> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1 - | -LL | fn user<T>() where S<T>::P: std::fmt::Debug {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires computing normalized predicates of `user`... - --> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1 - | -LL | fn user<T>() where S<T>::P: std::fmt::Debug {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires computing predicates of `user`, completing the cycle -note: cycle used when checking that `user` is well-formed - --> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1 - | -LL | fn user<T>() where S<T>::P: std::fmt::Debug {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error[E0392]: type parameter `T` is never used - --> $DIR/cycle-iat-inside-of-where-predicate.rs:10:10 - | -LL | struct S<T>; - | ^ unused type parameter - | - = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0391, E0392. -For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/associated-inherent-types/candidate-with-alias-2.rs b/tests/ui/associated-inherent-types/candidate-with-alias-2.rs new file mode 100644 index 00000000000..551d30a8786 --- /dev/null +++ b/tests/ui/associated-inherent-types/candidate-with-alias-2.rs @@ -0,0 +1,29 @@ +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +// A behaviour test showcasing that we do not normalize associated types in +// the impl self ty when assembling IAT candidates + +trait Identity { + type Assoc; +} +impl<T> Identity for T { + type Assoc = T; +} + +struct Foo<T>(T); +impl Foo<<u8 as Identity>::Assoc> { + type Inherent = u8; +} +impl Foo<<u16 as Identity>::Assoc> { + type Inherent = u32; +} + +struct Bar { + field: <Foo<u8>>::Inherent, + //~^ ERROR: multiple applicable items in scope +} + +fn main() { + Bar { field: 10_u8 }; +} diff --git a/tests/ui/associated-inherent-types/candidate-with-alias-2.stderr b/tests/ui/associated-inherent-types/candidate-with-alias-2.stderr new file mode 100644 index 00000000000..2b79b65f22b --- /dev/null +++ b/tests/ui/associated-inherent-types/candidate-with-alias-2.stderr @@ -0,0 +1,20 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/candidate-with-alias-2.rs:23:23 + | +LL | field: <Foo<u8>>::Inherent, + | ^^^^^^^^ multiple `Inherent` found + | +note: candidate #1 is defined in an impl for the type `Foo<<u8 as Identity>::Assoc>` + --> $DIR/candidate-with-alias-2.rs:16:5 + | +LL | type Inherent = u8; + | ^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Foo<<u16 as Identity>::Assoc>` + --> $DIR/candidate-with-alias-2.rs:19:5 + | +LL | type Inherent = u32; + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/associated-inherent-types/candidate-with-alias.rs b/tests/ui/associated-inherent-types/candidate-with-alias.rs new file mode 100644 index 00000000000..a84da195c26 --- /dev/null +++ b/tests/ui/associated-inherent-types/candidate-with-alias.rs @@ -0,0 +1,30 @@ +//@ check-pass + +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +// A behaviour test showcasing that IAT resolution can pick the right +// candidate even if it has an alias, if it's the only candidate. + +trait Identity { + type Assoc; +} +impl<T> Identity for T { + type Assoc = T; +} + +struct Foo<T>(T); +impl Foo<<u8 as Identity>::Assoc> { + type Inherent = u8; +} +impl Foo<u16> { + type Inherent = u32; +} + +struct Bar { + field: <Foo<u8>>::Inherent, +} + +fn main() { + Bar { field: 10_u8 }; +} diff --git a/tests/ui/associated-inherent-types/iat-in-where-bound.rs b/tests/ui/associated-inherent-types/iat-in-where-bound.rs new file mode 100644 index 00000000000..3b8b95eec9a --- /dev/null +++ b/tests/ui/associated-inherent-types/iat-in-where-bound.rs @@ -0,0 +1,14 @@ +//@ check-pass + +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +fn user<T: Copy>() where S<T>::P: std::fmt::Debug {} + +struct S<T>(T); + +impl<T: Copy> S<T> { + type P = (); +} + +fn main() {} diff --git a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.rs b/tests/ui/associated-inherent-types/iat-inside-of-adt.rs index 64168cb8c14..3d88016d0f8 100644 --- a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.rs +++ b/tests/ui/associated-inherent-types/iat-inside-of-adt.rs @@ -1,8 +1,7 @@ -//@ known-bug: #108491 +//@ check-pass #![feature(inherent_associated_types)] #![allow(incomplete_features)] -// FIXME(inherent_associated_types): This should pass. struct Foo { bar: Self::Bar, @@ -11,4 +10,8 @@ impl Foo { pub type Bar = usize; } -fn main() {} +fn main() { + Foo { + bar: 10_usize, + }; +} diff --git a/tests/ui/associated-inherent-types/impl_params_are_infers.rs b/tests/ui/associated-inherent-types/impl_params_are_infers.rs new file mode 100644 index 00000000000..55d29a35a23 --- /dev/null +++ b/tests/ui/associated-inherent-types/impl_params_are_infers.rs @@ -0,0 +1,34 @@ +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +// Test whether IAT resolution in item signatures will actually instantiate the +// impl's params with infers before equating self types, or if we "cheat" and +// use a heuristic (e.g. DeepRejectCtxt). + +struct Foo<T, U, V>(T, U, V); + +impl<T> Foo<T, T, u8> { + type IAT = u8; +} + +impl<T, U> Foo<T, U, u16> { + type IAT = u16; +} + +trait Identity { + type This; +} +impl<T> Identity for T { + type This = T; +} + +struct Bar<T, U> { + // It would be illegal to resolve to `Foo<T, T, u8>::IAT` as `T` and `U` are + // different types. However, currently we treat all impl-side params sort of like + // they're infers and assume they can unify with anything, so we consider it a + // valid candidate. + field: Foo<T, U, <u16 as Identity>::This>::IAT, + //~^ ERROR: multiple applicable items in scope +} + +fn main() {} diff --git a/tests/ui/associated-inherent-types/impl_params_are_infers.stderr b/tests/ui/associated-inherent-types/impl_params_are_infers.stderr new file mode 100644 index 00000000000..fd31693cbed --- /dev/null +++ b/tests/ui/associated-inherent-types/impl_params_are_infers.stderr @@ -0,0 +1,20 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/impl_params_are_infers.rs:30:48 + | +LL | field: Foo<T, U, <u16 as Identity>::This>::IAT, + | ^^^ multiple `IAT` found + | +note: candidate #1 is defined in an impl for the type `Foo<T, T, u8>` + --> $DIR/impl_params_are_infers.rs:11:5 + | +LL | type IAT = u8; + | ^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Foo<T, U, u16>` + --> $DIR/impl_params_are_infers.rs:15:5 + | +LL | type IAT = u16; + | ^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/crashes/125879.rs b/tests/ui/associated-inherent-types/inhabited-predicates.rs index 4318842e455..2b041d4e1be 100644 --- a/tests/crashes/125879.rs +++ b/tests/ui/associated-inherent-types/inhabited-predicates.rs @@ -1,8 +1,10 @@ -//@ known-bug: rust-lang/rust#125879 +//@ check-pass + #![feature(inherent_associated_types)] -#![allow(incomplete_features)] +#![expect(incomplete_features)] pub type PubAlias0 = PubTy::PrivAssocTy; +//~^ WARN: associated type `PubTy::PrivAssocTy` is more private than the item `PubAlias0` pub struct PubTy; impl PubTy { @@ -10,6 +12,7 @@ impl PubTy { } pub struct S(pub PubAlias0); +//~^ WARN: associated type `PubTy::PrivAssocTy` is more private than the item `S::0` pub unsafe fn foo(a: S) -> S { a diff --git a/tests/ui/associated-inherent-types/inhabited-predicates.stderr b/tests/ui/associated-inherent-types/inhabited-predicates.stderr new file mode 100644 index 00000000000..e43cd034e67 --- /dev/null +++ b/tests/ui/associated-inherent-types/inhabited-predicates.stderr @@ -0,0 +1,27 @@ +warning: associated type `PubTy::PrivAssocTy` is more private than the item `PubAlias0` + --> $DIR/inhabited-predicates.rs:6:1 + | +LL | pub type PubAlias0 = PubTy::PrivAssocTy; + | ^^^^^^^^^^^^^^^^^^ type alias `PubAlias0` is reachable at visibility `pub` + | +note: but associated type `PubTy::PrivAssocTy` is only usable at visibility `pub(crate)` + --> $DIR/inhabited-predicates.rs:11:5 + | +LL | type PrivAssocTy = (); + | ^^^^^^^^^^^^^^^^ + = note: `#[warn(private_interfaces)]` on by default + +warning: associated type `PubTy::PrivAssocTy` is more private than the item `S::0` + --> $DIR/inhabited-predicates.rs:14:14 + | +LL | pub struct S(pub PubAlias0); + | ^^^^^^^^^^^^^ field `S::0` is reachable at visibility `pub` + | +note: but associated type `PubTy::PrivAssocTy` is only usable at visibility `pub(crate)` + --> $DIR/inhabited-predicates.rs:11:5 + | +LL | type PrivAssocTy = (); + | ^^^^^^^^^^^^^^^^ + +warning: 2 warnings emitted + diff --git a/tests/ui/associated-inherent-types/issue-109299-1.rs b/tests/ui/associated-inherent-types/issue-109299-1.rs index 4546785f0b1..3132d9fef69 100644 --- a/tests/ui/associated-inherent-types/issue-109299-1.rs +++ b/tests/ui/associated-inherent-types/issue-109299-1.rs @@ -8,8 +8,6 @@ impl Lexer<i32> { } type X = impl for<T> Fn() -> Lexer<T>::Cursor; -//~^ ERROR associated type `Cursor` not found for `Lexer<T>` in the current scope -//~| ERROR associated type `Cursor` not found for `Lexer<T>` in the current scope -//~| ERROR: unconstrained opaque type +//~^ ERROR: unconstrained opaque type fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-109299-1.stderr b/tests/ui/associated-inherent-types/issue-109299-1.stderr index 6bc7a539680..bc8ea6acf28 100644 --- a/tests/ui/associated-inherent-types/issue-109299-1.stderr +++ b/tests/ui/associated-inherent-types/issue-109299-1.stderr @@ -6,31 +6,5 @@ LL | type X = impl for<T> Fn() -> Lexer<T>::Cursor; | = note: `X` must be used in combination with a concrete type within the same crate -error[E0220]: associated type `Cursor` not found for `Lexer<T>` in the current scope - --> $DIR/issue-109299-1.rs:10:40 - | -LL | struct Lexer<T>(T); - | --------------- associated type `Cursor` not found for this struct -... -LL | type X = impl for<T> Fn() -> Lexer<T>::Cursor; - | ^^^^^^ associated item not found in `Lexer<T>` - | - = note: the associated type was found for - - `Lexer<i32>` - -error[E0220]: associated type `Cursor` not found for `Lexer<T>` in the current scope - --> $DIR/issue-109299-1.rs:10:40 - | -LL | struct Lexer<T>(T); - | --------------- associated type `Cursor` not found for this struct -... -LL | type X = impl for<T> Fn() -> Lexer<T>::Cursor; - | ^^^^^^ associated item not found in `Lexer<T>` - | - = note: the associated type was found for - - `Lexer<i32>` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-1.rs b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-1.rs new file mode 100644 index 00000000000..7723ee9c58d --- /dev/null +++ b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-1.rs @@ -0,0 +1,23 @@ +//@ check-pass + +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +// Test that when resolving an IAT we select candidates based +// off whether the self type matches not just the name of the IAT + +struct Foo<T>(T); +impl Foo<u8> { + type Inherent = u8; +} +impl Foo<u16> { + type Inherent = u32; +} + +struct Bar { + field: <Foo<u16>>::Inherent, +} + +fn main() { + Bar { field: 10_u32 }; +} diff --git a/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.rs b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.rs new file mode 100644 index 00000000000..8a6d1896f7d --- /dev/null +++ b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.rs @@ -0,0 +1,29 @@ +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +// Test that when we have an unnormalized projection in the IAT self ty +// we don't normalize it to determine which IAT to resolve to. + +struct Foo<T>(T); +impl Foo<u8> { + type Inherent = u16; +} +impl Foo<u16> { + type Inherent = u32; +} + +struct Bar { + field: <Foo<<u8 as Identity>::This>>::Inherent, + //~^ ERROR: multiple applicable items in scope +} + +trait Identity { + type This; +} +impl<T> Identity for T { type This = T; } + +fn main() { + Bar { + field: 1_u16, + }; +} diff --git a/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.stderr b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.stderr new file mode 100644 index 00000000000..df8c124f77f --- /dev/null +++ b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.stderr @@ -0,0 +1,20 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/multiple-candidates-in-adt-field-2.rs:16:43 + | +LL | field: <Foo<<u8 as Identity>::This>>::Inherent, + | ^^^^^^^^ multiple `Inherent` found + | +note: candidate #1 is defined in an impl for the type `Foo<u8>` + --> $DIR/multiple-candidates-in-adt-field-2.rs:9:5 + | +LL | type Inherent = u16; + | ^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Foo<u16>` + --> $DIR/multiple-candidates-in-adt-field-2.rs:12:5 + | +LL | type Inherent = u32; + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-3.rs b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-3.rs new file mode 100644 index 00000000000..4c5b382463d --- /dev/null +++ b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-3.rs @@ -0,0 +1,27 @@ +//@ check-pass + +#![feature(inherent_associated_types, lazy_type_alias)] +#![expect(incomplete_features)] + +// Test that we *do* normalize free aliases in order to resolve +// between multiple IAT candidates + +type Free = u8; + +struct Foo<T>(T); +impl Foo<u8> { + type Assoc = u16; +} +impl Foo<u16> { + type Assoc = u32; +} + +struct Bar { + field: <Foo<Free>>::Assoc, +} + +fn main() { + Bar { + field: 1_u16, + }; +} diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs index c205cb800d2..337fd8fa00c 100644 --- a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs +++ b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs @@ -27,5 +27,5 @@ impl S<()> { fn main() { let _: S::<bool>::Pr = (); //[shadowed]~^ ERROR associated type `Pr` not found - //[uncovered]~^^ ERROR ambiguous associated type + //[uncovered]~^^ ERROR associated type `Pr` not found } diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr index 3e914e0538d..f35158c5b41 100644 --- a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr +++ b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr @@ -1,15 +1,15 @@ -error[E0223]: ambiguous associated type - --> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:12 +error[E0220]: associated type `Pr` not found for `S<bool>` in the current scope + --> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:23 | +LL | struct S<T>(T); + | ----------- associated type `Pr` not found for this struct +... LL | let _: S::<bool>::Pr = (); - | ^^^^^^^^^^^^^ - | -help: use fully-qualified syntax - | -LL - let _: S::<bool>::Pr = (); -LL + let _: <S<bool> as Tr>::Pr = (); + | ^^ associated item not found in `S<bool>` | + = note: the associated type was found for + error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0223`. +For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-inherent-types/really_deep_self_ty_mismatch.rs b/tests/ui/associated-inherent-types/really_deep_self_ty_mismatch.rs new file mode 100644 index 00000000000..eac33f631bb --- /dev/null +++ b/tests/ui/associated-inherent-types/really_deep_self_ty_mismatch.rs @@ -0,0 +1,26 @@ +//@ check-pass + +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +// Test that IAT resolution doesn't bail out when the self type is +// very nested. + +struct Foo<T>(T); +#[rustfmt::skip] +impl Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<u8>>>>>>>>>>> { + type Inherent = u16; +} +#[rustfmt::skip] +impl Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<u16>>>>>>>>>>> { + type Inherent = u32; +} + +#[rustfmt::skip] +struct Bar { + field: <Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<Foo<u8>>>>>>>>>>>>::Inherent, +} + +fn main() { + Bar { field: 1_u16 }; +} |
