diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 8a2edd843f209..e4b12d293ab92 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -35,16 +35,22 @@ use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause}; use rustc_middle::hir::nested_filter; 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; @@ -444,6 +450,68 @@ 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, + ) -> (Vec, Vec>) { + 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 seems dubious 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); + + // We make an infcx and replace any escaping vars with placeholders so that IAT res + // with type/const bound vars in arguments is slightly smarter. `for >::IAT` + // would otherwise unify with `impl Foo` when ideally we would not. + let infcx = self.tcx().infer_ctxt().build(TypingMode::non_body_analysis()); + let mut universes = if self_ty.has_escaping_bound_vars() { + vec![None; self_ty.outer_exclusive_binder().as_usize()] + } else { + vec![] + }; + let candidates = + rustc_trait_selection::traits::with_replaced_escaping_bound_vars( + &infcx, + &mut universes, + self_ty, + |self_ty| { + 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 Foo` to unify with `Foo::IAT`, while also disallowing + // `Foo::IAT` from unifying with `impl Foo`. + // + // 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 Foo` would + // be considered a valid candidate when resolving `Foo::IAT`. + 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 45fee0fa4024e..f62e149191da0 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, @@ -742,7 +743,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, name: Ident, self_ty: Ty<'tcx>, - candidates: Vec<(DefId, (DefId, DefId))>, + candidates: Vec, fulfillment_errors: Vec>, span: Span, assoc_tag: ty::AssocTag, @@ -776,8 +777,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::>() .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 2a37a8bdbd47d..2fb8752c0a753 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, + ) -> (Vec, Vec>); + /// 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 @@ -1445,48 +1460,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); @@ -1503,78 +1502,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 cfb25deac0e04..ccad4a12ea615 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; @@ -308,6 +312,74 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { )) } + fn select_inherent_assoc_candidates( + &self, + span: Span, + self_ty: Ty<'tcx>, + candidates: Vec, + ) -> (Vec, Vec>) { + let tcx = self.tcx(); + let infcx = &self.infcx; + + let mut universes = if self_ty.has_escaping_bound_vars() { + vec![None; self_ty.outer_exclusive_binder().as_usize()] + } else { + vec![] + }; + + let mut fulfillment_errors = vec![]; + let candidates = + traits::with_replaced_escaping_bound_vars(infcx, &mut universes, self_ty, |self_ty| { + candidates + .into_iter() + .filter(|&InherentAssocCandidate { impl_, .. }| { + infcx.probe(|_| { + 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 + }) + }) + .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 d8bab58545fcc..2a336cc21f492 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 34502f4955003..cce207faaa381 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -238,6 +238,13 @@ impl bool { + if lhs == rhs { + return true; + } + 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 e7d7de23bfeba..0000000000000 --- 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; - -struct Test; - -impl Test { - 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 index f400c02de8d6f..d0f91b748401e 100644 --- a/tests/crashes/138131.rs +++ b/tests/crashes/138131.rs @@ -1,12 +1,15 @@ //@ known-bug: #138131 -#![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] + +#![feature(min_generic_const_args, generic_const_items)] + +const BAR<'a>: usize = 10; + struct Foo<'a> { x: &'a (), } impl<'a> Foo<'a> { - fn foo(_: [u8; Foo::X]) {} + fn foo(_: [u8; BAR]) {} } fn main() {} diff --git a/tests/crashes/138166.rs b/tests/crashes/138166.rs index 98003bd6dae77..2d95b65384f92 100644 --- a/tests/crashes/138166.rs +++ b/tests/crashes/138166.rs @@ -1,7 +1,10 @@ //@ known-bug: #138166 -#![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] -struct a(Box<[u8; Box::b]>); + +#![feature(min_generic_const_args, generic_const_items)] + +const FOO: usize = 10; + +struct a(Box<[u8; FOO]>); impl a { fn c(self) { self.0.d() } } diff --git a/tests/crashes/138240.rs b/tests/crashes/138240.rs deleted file mode 100644 index 6ffb7868bd5d8..0000000000000 --- a/tests/crashes/138240.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #138240 -//@edition:2024 -#![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] -async fn _CF() -> Box<[u8; Box::b]> { - Box::new(true) -} - -fn main() {} diff --git a/tests/crashes/138266.rs b/tests/crashes/138266.rs deleted file mode 100644 index 9a4de9abcff5c..0000000000000 --- a/tests/crashes/138266.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ known-bug: #138266 -//@compile-flags: --crate-type=lib -#![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] -pub fn f(mut x: [u8; Box::b]) { - x[72] = 1; -} diff --git a/tests/crashes/138359.rs b/tests/crashes/138359.rs index d4376d536eecc..0aedac08ba44a 100644 --- a/tests/crashes/138359.rs +++ b/tests/crashes/138359.rs @@ -1,7 +1,11 @@ //@ known-bug: #138359 + #![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] -struct a(Box<[u8; Box::b]>); +#![feature(generic_const_items)] + +const FOO: usize = 10; + +struct a(Box<[u8; FOO]>); impl a { fn c(self) { self.0.da } } 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 0000000000000..276e3cf1da044 --- /dev/null +++ b/tests/ui/associated-inherent-types/bound_vars_in_args.rs @@ -0,0 +1,23 @@ +#![feature(non_lifetime_binders, inherent_associated_types)] +#![expect(incomplete_features)] + +// Test that we can resolve to the right IAT when the self type +// contains a bound type. + +struct Foo(T); + +impl Foo<[u8]> { + type IAT = u8; +} + +impl Foo { + type IAT = u8; +} + +struct Bar +//~^ ERROR: the size for values of type `T` cannot be known at compilation time +//~| ERROR: the size for values of type `T` cannot be known at compilation time +where + for Foo::IAT: Sized; + +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 0000000000000..108f1e531af68 --- /dev/null +++ b/tests/ui/associated-inherent-types/bound_vars_in_args.stderr @@ -0,0 +1,37 @@ +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/bound_vars_in_args.rs:17:1 + | +LL | struct Bar + | ^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `T` +note: required by a bound in `Foo::IAT` + --> $DIR/bound_vars_in_args.rs:13:9 + | +LL | impl Foo { + | ^^^^^ required by this bound in `Foo::IAT` +LL | type IAT = u8; + | --- required by a bound in this associated type + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/bound_vars_in_args.rs:17:1 + | +LL | / struct Bar +LL | | +LL | | +LL | | where +LL | | for Foo::IAT: Sized; + | |______________________________^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `T` +note: required by a bound in `Foo::IAT` + --> $DIR/bound_vars_in_args.rs:13:9 + | +LL | impl Foo { + | ^^^^^ required by this bound in `Foo::IAT` +LL | type IAT = u8; + | --- required by a bound in this associated type + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. 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 7f8ed89852522..0000000000000 --- 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 902094b986286..0000000000000 --- 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() where S::P: std::fmt::Debug {} - -struct S; - -impl S { - 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 e97a5df9d4917..0000000000000 --- 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() where S::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() where S::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() where S::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() where S::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; - | ^ 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 0000000000000..d7be825a9c22e --- /dev/null +++ b/tests/ui/associated-inherent-types/candidate-with-alias-2.rs @@ -0,0 +1,26 @@ +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +trait Identity { + type Assoc; +} +impl Identity for T { + type Assoc = T; +} + +struct Foo(T); +impl Foo<::Assoc> { + type Inherent = u8; +} +impl Foo<::Assoc> { + type Inherent = u32; +} + +struct Bar { + field: >::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 0000000000000..335e35a95778d --- /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:20:23 + | +LL | field: >::Inherent, + | ^^^^^^^^ multiple `Inherent` found + | +note: candidate #1 is defined in an impl for the type `Foo<::Assoc>` + --> $DIR/candidate-with-alias-2.rs:13:5 + | +LL | type Inherent = u8; + | ^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Foo<::Assoc>` + --> $DIR/candidate-with-alias-2.rs:16: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 0000000000000..d4dd002a77415 --- /dev/null +++ b/tests/ui/associated-inherent-types/candidate-with-alias.rs @@ -0,0 +1,27 @@ +//@ check-pass + +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +trait Identity { + type Assoc; +} +impl Identity for T { + type Assoc = T; +} + +struct Foo(T); +impl Foo<::Assoc> { + type Inherent = u8; +} +impl Foo { + type Inherent = u32; +} + +struct Bar { + field: >::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 0000000000000..3b8b95eec9a42 --- /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() where S::P: std::fmt::Debug {} + +struct S(T); + +impl S { + 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 similarity index 61% rename from tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.rs rename to tests/ui/associated-inherent-types/iat-inside-of-adt.rs index 64168cb8c14f8..3d88016d0f87b 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 0000000000000..55d29a35a231a --- /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); + +impl Foo { + type IAT = u8; +} + +impl Foo { + type IAT = u16; +} + +trait Identity { + type This; +} +impl Identity for T { + type This = T; +} + +struct Bar { + // It would be illegal to resolve to `Foo::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::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 0000000000000..fd31693cbedc2 --- /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::This>::IAT, + | ^^^ multiple `IAT` found + | +note: candidate #1 is defined in an impl for the type `Foo` + --> $DIR/impl_params_are_infers.rs:11:5 + | +LL | type IAT = u8; + | ^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Foo` + --> $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 similarity index 50% rename from tests/crashes/125879.rs rename to tests/ui/associated-inherent-types/inhabited-predicates.rs index 4318842e45518..2b041d4e1be20 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 0000000000000..e43cd034e6758 --- /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/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 0000000000000..7723ee9c58d90 --- /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); +impl Foo { + type Inherent = u8; +} +impl Foo { + type Inherent = u32; +} + +struct Bar { + field: >::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 0000000000000..b942c303d3e84 --- /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 we don't normalize it +// to determine which IAT to resolve to. + +struct Foo(T); +impl Foo { + type Inherent = u16; +} +impl Foo { + type Inherent = u32; +} + +struct Bar { + field: ::This>>::Inherent, + //~^ ERROR: multiple applicable items in scope +} + +trait Identity { + type This; +} +impl 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 0000000000000..df8c124f77fab --- /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: ::This>>::Inherent, + | ^^^^^^^^ multiple `Inherent` found + | +note: candidate #1 is defined in an impl for the type `Foo` + --> $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` + --> $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 0000000000000..4c5b382463d54 --- /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); +impl Foo { + type Assoc = u16; +} +impl Foo { + type Assoc = u32; +} + +struct Bar { + field: >::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 c205cb800d2f6..337fd8fa00c55 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::::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 3e914e0538d0b..f35158c5b4101 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` in the current scope + --> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:23 | +LL | struct S(T); + | ----------- associated type `Pr` not found for this struct +... LL | let _: S::::Pr = (); - | ^^^^^^^^^^^^^ - | -help: use fully-qualified syntax - | -LL - let _: S::::Pr = (); -LL + let _: as Tr>::Pr = (); + | ^^ associated item not found in `S` | + = 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 0000000000000..eac33f631bbc4 --- /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); +#[rustfmt::skip] +impl Foo>>>>>>>>>> { + type Inherent = u16; +} +#[rustfmt::skip] +impl Foo>>>>>>>>>> { + type Inherent = u32; +} + +#[rustfmt::skip] +struct Bar { + field: >>>>>>>>>>>::Inherent, +} + +fn main() { + Bar { field: 1_u16 }; +} diff --git a/tests/ui/const-generics/mgca/unresolved-iac-1.rs b/tests/ui/const-generics/mgca/unresolved-iac-1.rs new file mode 100644 index 0000000000000..a0700aa5b65f4 --- /dev/null +++ b/tests/ui/const-generics/mgca/unresolved-iac-1.rs @@ -0,0 +1,11 @@ +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +struct A(Box<[u8; Box::b]>); +//~^ ERROR: associated constant `b` not found for + +impl A { + fn c(self) { self.0.d() } +} +fn main() {} diff --git a/tests/ui/const-generics/mgca/unresolved-iac-1.stderr b/tests/ui/const-generics/mgca/unresolved-iac-1.stderr new file mode 100644 index 0000000000000..4bf1191e786a5 --- /dev/null +++ b/tests/ui/const-generics/mgca/unresolved-iac-1.stderr @@ -0,0 +1,16 @@ +error[E0220]: associated constant `b` not found for `Box<{type error}, {type error}>` in the current scope + --> $DIR/unresolved-iac-1.rs:5:24 + | +LL | struct A(Box<[u8; Box::b]>); + | ^ associated item not found in `Box<{type error}, {type error}>` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL + | + = note: associated constant `b` not found for this struct + | + = note: the associated constant was found for + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/const-generics/mgca/unresolved-iac-2.rs b/tests/ui/const-generics/mgca/unresolved-iac-2.rs new file mode 100644 index 0000000000000..72bb5d7f627a2 --- /dev/null +++ b/tests/ui/const-generics/mgca/unresolved-iac-2.rs @@ -0,0 +1,14 @@ +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +struct Foo<'a> { + x: &'a (), +} + +impl<'a> Foo<'a> { + fn foo(_: [u8; Foo::X]) {} + //~^ ERROR: associated constant `X` not found for `Foo<'_>` in the current scope +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/unresolved-iac-2.stderr b/tests/ui/const-generics/mgca/unresolved-iac-2.stderr new file mode 100644 index 0000000000000..a6c12877a4e09 --- /dev/null +++ b/tests/ui/const-generics/mgca/unresolved-iac-2.stderr @@ -0,0 +1,15 @@ +error[E0220]: associated constant `X` not found for `Foo<'_>` in the current scope + --> $DIR/unresolved-iac-2.rs:10:25 + | +LL | struct Foo<'a> { + | -------------- associated constant `X` not found for this struct +... +LL | fn foo(_: [u8; Foo::X]) {} + | ^ associated item not found in `Foo<'_>` + | + = note: the associated constant was found for + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0220`.