diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs index 1bee9632110bd..2a4f9db8963c8 100644 --- a/compiler/rustc_infer/src/infer/projection.rs +++ b/compiler/rustc_infer/src/infer/projection.rs @@ -1,7 +1,8 @@ use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty; use super::InferCtxt; +use crate::infer::Term; use crate::traits::{Obligation, PredicateObligations}; impl<'tcx> InferCtxt<'tcx> { @@ -11,24 +12,32 @@ impl<'tcx> InferCtxt<'tcx> { /// of the given projection. This allows us to proceed with projections /// while they cannot be resolved yet due to missing information or /// simply due to the lack of access to the trait resolution machinery. - pub fn projection_ty_to_infer( + pub fn projection_term_to_infer( &self, param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::AliasTy<'tcx>, + alias_term: ty::AliasTerm<'tcx>, cause: ObligationCause<'tcx>, recursion_depth: usize, obligations: &mut PredicateObligations<'tcx>, - ) -> Ty<'tcx> { + ) -> Term<'tcx> { debug_assert!(!self.next_trait_solver()); - let ty_var = self.next_ty_var(self.tcx.def_span(projection_ty.def_id)); + + let span = self.tcx.def_span(alias_term.def_id); + let infer_var = if alias_term.kind(self.tcx).is_type() { + self.next_ty_var(span).into() + } else { + self.next_const_var(span).into() + }; + let projection = ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { - projection_term: projection_ty.into(), - term: ty_var.into(), + projection_term: alias_term, + term: infer_var, })); let obligation = Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection); obligations.push(obligation); - ty_var + + infer_var } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3ea285d3d8eb8..0f7f8527088c4 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -243,10 +243,18 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ty::AliasTermKind::ProjectionTy } } + DefKind::AssocConst => { + if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id)) + { + ty::AliasTermKind::InherentConst + } else { + ty::AliasTermKind::ProjectionConst + } + } DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy, DefKind::TyAlias => ty::AliasTermKind::FreeTy, - DefKind::AssocConst => ty::AliasTermKind::ProjectionConst, - DefKind::AnonConst | DefKind::Const | DefKind::Ctor(_, CtorKind::Const) => { + DefKind::Const => ty::AliasTermKind::FreeConst, + DefKind::AnonConst | DefKind::Ctor(_, CtorKind::Const) => { ty::AliasTermKind::UnevaluatedConst } kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index ad8677f7c7da2..af90c2fb95dab 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3195,7 +3195,7 @@ define_print! { ty::AliasTerm<'tcx> { match self.kind(cx.tcx()) { - ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)), + ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => p!(pretty_print_inherent_projection(*self)), ty::AliasTermKind::ProjectionTy => { if !(cx.should_print_verbose() || with_reduced_queries()) && cx.tcx().is_impl_trait_in_trait(self.def_id) @@ -3205,7 +3205,8 @@ define_print! { p!(print_def_path(self.def_id, self.args)); } } - | ty::AliasTermKind::FreeTy + ty::AliasTermKind::FreeTy + | ty::AliasTermKind::FreeConst | ty::AliasTermKind::OpaqueTy | ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index f5158edffcff4..6fe5927c29fcb 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -966,7 +966,9 @@ impl<'tcx> TyCtxt<'tcx> { } ty::AliasTermKind::OpaqueTy => Some(self.variances_of(def_id)), ty::AliasTermKind::InherentTy + | ty::AliasTermKind::InherentConst | ty::AliasTermKind::FreeTy + | ty::AliasTermKind::FreeConst | ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => None, } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8e69ff568b928..4a7e98f24ae32 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -568,6 +568,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // Lower the named constant to a THIR pattern. let args = self.typeck_results.node_args(id); + // FIXME(mgca): we will need to special case IACs here to have type system compatible + // generic args, instead of how we represent them in body expressions. let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args }); let mut pattern = self.const_to_pat(c, ty, id, span); diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs index d077f8a9be8ad..8aa6e4a3d7118 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs @@ -19,19 +19,25 @@ where goal: Goal>, ) -> QueryResult { let cx = self.cx(); - let free_ty = goal.predicate.alias; + let free_alias = goal.predicate.alias; // Check where clauses self.add_goals( GoalSource::Misc, - cx.predicates_of(free_ty.def_id) - .iter_instantiated(cx, free_ty.args) + cx.predicates_of(free_alias.def_id) + .iter_instantiated(cx, free_alias.args) .map(|pred| goal.with(cx, pred)), ); - let actual = cx.type_of(free_ty.def_id).instantiate(cx, free_ty.args); - self.instantiate_normalizes_to_term(goal, actual.into()); + let actual = if free_alias.kind(cx).is_type() { + cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args) + } else { + // FIXME(mgca): once const items are actual aliases defined as equal to type system consts + // this should instead return that. + panic!("normalizing free const aliases in the type system is unsupported"); + }; + self.instantiate_normalizes_to_term(goal, actual.into()); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 1d1ff09ee4104..2640238f5a904 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -15,12 +15,12 @@ where D: SolverDelegate, I: Interner, { - pub(super) fn normalize_inherent_associated_type( + pub(super) fn normalize_inherent_associated_term( &mut self, goal: Goal>, ) -> QueryResult { let cx = self.cx(); - let inherent = goal.predicate.alias.expect_ty(cx); + let inherent = goal.predicate.alias; let impl_def_id = cx.parent(inherent.def_id); let impl_args = self.fresh_args_for_item(impl_def_id); @@ -48,8 +48,13 @@ where .map(|pred| goal.with(cx, pred)), ); - let normalized = cx.type_of(inherent.def_id).instantiate(cx, inherent_args); - self.instantiate_normalizes_to_term(goal, normalized.into()); + let normalized = if inherent.kind(cx).is_type() { + cx.type_of(inherent.def_id).instantiate(cx, inherent_args).into() + } else { + // FIXME(mgca): Properly handle IACs in the type system + panic!("normalizing inherent associated consts in the type system is unsupported"); + }; + self.instantiate_normalizes_to_term(goal, normalized); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index b030af483817e..400b4ce1200cb 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -48,9 +48,13 @@ where }) }) } - ty::AliasTermKind::InherentTy => self.normalize_inherent_associated_type(goal), + ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => { + self.normalize_inherent_associated_term(goal) + } ty::AliasTermKind::OpaqueTy => self.normalize_opaque_type(goal), - ty::AliasTermKind::FreeTy => self.normalize_free_alias(goal), + ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst => { + self.normalize_free_alias(goal) + } ty::AliasTermKind::UnevaluatedConst => self.normalize_anon_const(goal), } } @@ -333,6 +337,8 @@ where cx.type_of(target_item_def_id).map_bound(|ty| ty.into()) } ty::AliasTermKind::ProjectionConst => { + // FIXME(mgca): once const items are actual aliases defined as equal to type system consts + // this should instead return that. if cx.features().associated_const_equality() { panic!("associated const projection is not supported yet") } else { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 0987c5b42d881..5b938456e03b0 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -51,7 +51,7 @@ pub use self::dyn_compatibility::{ pub use self::engine::{ObligationCtxt, TraitEngineExt}; pub use self::fulfill::{FulfillmentContext, OldSolverError, PendingPredicateObligation}; pub use self::normalize::NormalizeExt; -pub use self::project::{normalize_inherent_projection, normalize_projection_ty}; +pub use self::project::{normalize_inherent_projection, normalize_projection_term}; pub use self::select::{ EvaluationCache, EvaluationResult, IntercrateAmbiguityCause, OverflowError, SelectionCache, SelectionContext, diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 5f0acd46f86ae..88a0c402702e1 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -1,6 +1,7 @@ //! Deeply normalize types using the old trait solver. use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_hir::def::DefKind; use rustc_infer::infer::at::At; use rustc_infer::infer::{InferCtxt, InferOk}; use rustc_infer::traits::{ @@ -10,15 +11,12 @@ use rustc_macros::extension; use rustc_middle::span_bug; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, - TypingMode, + self, AliasTerm, Term, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, + TypeVisitableExt, TypingMode, }; use tracing::{debug, instrument}; -use super::{ - BoundVarReplacer, PlaceholderReplacer, SelectionContext, project, - with_replaced_escaping_bound_vars, -}; +use super::{BoundVarReplacer, PlaceholderReplacer, SelectionContext, project}; use crate::error_reporting::InferCtxtErrorExt; use crate::error_reporting::traits::OverflowCause; use crate::solve::NextSolverError; @@ -178,6 +176,163 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { if !needs_normalization(self.selcx.infcx, &value) { value } else { value.fold_with(self) } } + + // FIXME(mgca): While this supports constants, it is only used for types by default right now + #[instrument(level = "debug", skip(self), ret)] + fn normalize_trait_projection(&mut self, proj: AliasTerm<'tcx>) -> Term<'tcx> { + if !proj.has_escaping_bound_vars() { + // When we don't have escaping bound vars we can normalize ambig aliases + // to inference variables (done in `normalize_projection_ty`). This would + // be wrong if there were escaping bound vars as even if we instantiated + // the bound vars with placeholders, we wouldn't be able to map them back + // after normalization succeeded. + // + // Also, as an optimization: when we don't have escaping bound vars, we don't + // need to replace them with placeholders (see branch below). + let proj = proj.fold_with(self); + project::normalize_projection_term( + self.selcx, + self.param_env, + proj, + self.cause.clone(), + self.depth, + self.obligations, + ) + } else { + // If there are escaping bound vars, we temporarily replace the + // bound vars with placeholders. Note though, that in the case + // that we still can't project for whatever reason (e.g. self + // type isn't known enough), we *can't* register an obligation + // and return an inference variable (since then that obligation + // would have bound vars and that's a can of worms). Instead, + // we just give up and fall back to pretending like we never tried! + // + // Note: this isn't necessarily the final approach here; we may + // want to figure out how to register obligations with escaping vars + // or handle this some other way. + let infcx = self.selcx.infcx; + let (proj, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, proj); + let proj = proj.fold_with(self); + let normalized_term = project::opt_normalize_projection_term( + self.selcx, + self.param_env, + proj, + self.cause.clone(), + self.depth, + self.obligations, + ) + .ok() + .flatten() + .unwrap_or(proj.to_term(infcx.tcx)); + + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + normalized_term, + ) + } + } + + // FIXME(mgca): While this supports constants, it is only used for types by default right now + #[instrument(level = "debug", skip(self), ret)] + fn normalize_inherent_projection(&mut self, inherent: AliasTerm<'tcx>) -> Term<'tcx> { + if !inherent.has_escaping_bound_vars() { + // When we don't have escaping bound vars we can normalize ambig aliases + // to inference variables (done in `normalize_projection_ty`). This would + // be wrong if there were escaping bound vars as even if we instantiated + // the bound vars with placeholders, we wouldn't be able to map them back + // after normalization succeeded. + // + // Also, as an optimization: when we don't have escaping bound vars, we don't + // need to replace them with placeholders (see branch below). + + let inherent = inherent.fold_with(self); + project::normalize_inherent_projection( + self.selcx, + self.param_env, + inherent, + self.cause.clone(), + self.depth, + self.obligations, + ) + } else { + let infcx = self.selcx.infcx; + let (inherent, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, inherent); + let inherent = inherent.fold_with(self); + let inherent = project::normalize_inherent_projection( + self.selcx, + self.param_env, + inherent, + self.cause.clone(), + self.depth, + self.obligations, + ); + + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + inherent, + ) + } + } + + // FIXME(mgca): While this supports constants, it is only used for types by default right now + #[instrument(level = "debug", skip(self), ret)] + fn normalize_free_alias(&mut self, free: AliasTerm<'tcx>) -> Term<'tcx> { + let recursion_limit = self.cx().recursion_limit(); + if !recursion_limit.value_within_limit(self.depth) { + self.selcx.infcx.err_ctxt().report_overflow_error( + OverflowCause::DeeplyNormalize(free.into()), + self.cause.span, + false, + |diag| { + diag.note(crate::fluent_generated::trait_selection_ty_alias_overflow); + }, + ); + } + + let infcx = self.selcx.infcx; + self.obligations.extend( + // FIXME(BoxyUwU): + // FIXME(lazy_type_alias): + // It seems suspicious to instantiate the predicates with arguments that might be bound vars, + // we might wind up instantiating one of these bound vars underneath a hrtb. + infcx.tcx.predicates_of(free.def_id).instantiate_own(infcx.tcx, free.args).map( + |(mut predicate, span)| { + if free.has_escaping_bound_vars() { + (predicate, ..) = BoundVarReplacer::replace_bound_vars( + infcx, + &mut self.universes, + predicate, + ); + } + let mut cause = self.cause.clone(); + cause.map_code(|code| ObligationCauseCode::TypeAlias(code, span, free.def_id)); + Obligation::new(infcx.tcx, cause, self.param_env, predicate) + }, + ), + ); + self.depth += 1; + let res = if free.kind(infcx.tcx).is_type() { + infcx.tcx.type_of(free.def_id).instantiate(infcx.tcx, free.args).fold_with(self).into() + } else { + // FIXME(mgca): once const items are actual aliases defined as equal to type system consts + // this should instead use that rather than evaluating. + super::evaluate_const(infcx, free.to_term(infcx.tcx).expect_const(), self.param_env) + .super_fold_with(self) + .into() + }; + self.depth -= 1; + res + } } impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx> { @@ -259,186 +414,63 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx } } - ty::Projection if !data.has_escaping_bound_vars() => { - // When we don't have escaping bound vars we can normalize ambig aliases - // to inference variables (done in `normalize_projection_ty`). This would - // be wrong if there were escaping bound vars as even if we instantiated - // the bound vars with placeholders, we wouldn't be able to map them back - // after normalization succeeded. - // - // Also, as an optimization: when we don't have escaping bound vars, we don't - // need to replace them with placeholders (see branch below). - let data = data.fold_with(self); - let normalized_ty = project::normalize_projection_ty( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ); - debug!( - ?self.depth, - ?ty, - ?normalized_ty, - obligations.len = ?self.obligations.len(), - "AssocTypeNormalizer: normalized type" - ); - normalized_ty.expect_type() - } - - ty::Projection => { - // If there are escaping bound vars, we temporarily replace the - // bound vars with placeholders. Note though, that in the case - // that we still can't project for whatever reason (e.g. self - // type isn't known enough), we *can't* register an obligation - // and return an inference variable (since then that obligation - // would have bound vars and that's a can of worms). Instead, - // we just give up and fall back to pretending like we never tried! - // - // Note: this isn't necessarily the final approach here; we may - // want to figure out how to register obligations with escaping vars - // or handle this some other way. - - let infcx = self.selcx.infcx; - let (data, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); - let data = data.fold_with(self); - let normalized_ty = project::opt_normalize_projection_term( - self.selcx, - self.param_env, - data.into(), - self.cause.clone(), - self.depth, - self.obligations, - ) - .ok() - .flatten() - .map(|term| term.expect_type()) - .map(|normalized_ty| { - PlaceholderReplacer::replace_placeholders( - infcx, - mapped_regions, - mapped_types, - mapped_consts, - &self.universes, - normalized_ty, - ) - }) - .unwrap_or_else(|| ty.super_fold_with(self)); - - debug!( - ?self.depth, - ?ty, - ?normalized_ty, - obligations.len = ?self.obligations.len(), - "AssocTypeNormalizer: normalized type" - ); - normalized_ty - } - ty::Free => { - let recursion_limit = self.cx().recursion_limit(); - if !recursion_limit.value_within_limit(self.depth) { - self.selcx.infcx.err_ctxt().report_overflow_error( - OverflowCause::DeeplyNormalize(data.into()), - self.cause.span, - false, - |diag| { - diag.note(crate::fluent_generated::trait_selection_ty_alias_overflow); - }, - ); - } - - let infcx = self.selcx.infcx; - self.obligations.extend( - infcx.tcx.predicates_of(data.def_id).instantiate_own(infcx.tcx, data.args).map( - |(mut predicate, span)| { - if data.has_escaping_bound_vars() { - (predicate, ..) = BoundVarReplacer::replace_bound_vars( - infcx, - &mut self.universes, - predicate, - ); - } - let mut cause = self.cause.clone(); - cause.map_code(|code| { - ObligationCauseCode::TypeAlias(code, span, data.def_id) - }); - Obligation::new(infcx.tcx, cause, self.param_env, predicate) - }, - ), - ); - self.depth += 1; - let res = infcx - .tcx - .type_of(data.def_id) - .instantiate(infcx.tcx, data.args) - .fold_with(self); - self.depth -= 1; - res - } - - ty::Inherent if !data.has_escaping_bound_vars() => { - // This branch is *mostly* just an optimization: when we don't - // have escaping bound vars, we don't need to replace them with - // placeholders (see branch below). *Also*, we know that we can - // register an obligation to *later* project, since we know - // there won't be bound vars there. - - let data = data.fold_with(self); - - project::normalize_inherent_projection( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ) - } - - ty::Inherent => { - let infcx = self.selcx.infcx; - let (data, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); - let data = data.fold_with(self); - let ty = project::normalize_inherent_projection( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ); - - PlaceholderReplacer::replace_placeholders( - infcx, - mapped_regions, - mapped_types, - mapped_consts, - &self.universes, - ty, - ) - } + ty::Projection => self.normalize_trait_projection(data.into()).expect_type(), + ty::Inherent => self.normalize_inherent_projection(data.into()).expect_type(), + ty::Free => self.normalize_free_alias(data.into()).expect_type(), } } #[instrument(skip(self), level = "debug")] - fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { let tcx = self.selcx.tcx(); - if tcx.features().generic_const_exprs() || !needs_normalization(self.selcx.infcx, &constant) - { - constant + if tcx.features().generic_const_exprs() || !needs_normalization(self.selcx.infcx, &ct) { + return ct; + } + + // Doing "proper" normalization of const aliases is inherently cyclic until const items + // are real aliases instead of having bodies. We gate proper const alias handling behind + // mgca to avoid breaking stable code, though this should become the "main" codepath long + // before mgca is stabilized. + // + // FIXME(BoxyUwU): Enabling this by default is blocked on a refactoring to how const items + // are represented. + if tcx.features().min_generic_const_args() { + let uv = match ct.kind() { + ty::ConstKind::Unevaluated(uv) => uv, + _ => return ct.super_fold_with(self), + }; + + let ct = match tcx.def_kind(uv.def) { + DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) { + DefKind::Trait => self.normalize_trait_projection(uv.into()), + DefKind::Impl { of_trait: false } => { + self.normalize_inherent_projection(uv.into()) + } + kind => unreachable!( + "unexpected `DefKind` for const alias' resolution's parent def: {:?}", + kind + ), + }, + DefKind::Const | DefKind::AnonConst => self.normalize_free_alias(uv.into()), + kind => { + unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind) + } + }; + + // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be + // unnormalized after const evaluation returns. + ct.expect_const().super_fold_with(self) } else { - let constant = constant.super_fold_with(self); - debug!(?constant, ?self.param_env); - with_replaced_escaping_bound_vars( + let ct = ct.super_fold_with(self); + return super::with_replaced_escaping_bound_vars( self.selcx.infcx, &mut self.universes, - constant, - |constant| super::evaluate_const(self.selcx.infcx, constant, self.param_env), + ct, + |ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env), ) - .super_fold_with(self) + .super_fold_with(self); + // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be + // unnormalized after const evaluation returns. } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index dd868c9d40eaf..ca58da5ca6d55 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -5,7 +5,6 @@ use std::ops::ControlFlow; use rustc_data_structures::sso::SsoHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorGuaranteed; -use rustc_hir::def::DefKind; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::resolve::OpportunisticRegionResolver; @@ -172,6 +171,7 @@ pub(super) enum ProjectAndUnifyResult<'tcx> { /// ``` /// If successful, this may result in additional obligations. Also returns /// the projection cache key used to track these additional obligations. +// FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "debug", skip(selcx))] pub(super) fn poly_project_and_unify_term<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, @@ -201,6 +201,7 @@ pub(super) fn poly_project_and_unify_term<'cx, 'tcx>( /// If successful, this may result in additional obligations. /// /// See [poly_project_and_unify_term] for an explanation of the return value. +// FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "debug", skip(selcx))] fn project_and_unify_term<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, @@ -258,34 +259,28 @@ fn project_and_unify_term<'cx, 'tcx>( /// there are unresolved type variables in the projection, we will /// instantiate it with a fresh type variable `$X` and generate a new /// obligation `::Item == $X` for later. -pub fn normalize_projection_ty<'a, 'b, 'tcx>( +// FIXME(mgca): While this supports constants, it is only used for types by default right now +pub fn normalize_projection_term<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::AliasTy<'tcx>, + alias_term: ty::AliasTerm<'tcx>, cause: ObligationCause<'tcx>, depth: usize, obligations: &mut PredicateObligations<'tcx>, ) -> Term<'tcx> { - opt_normalize_projection_term( - selcx, - param_env, - projection_ty.into(), - cause.clone(), - depth, - obligations, - ) - .ok() - .flatten() - .unwrap_or_else(move || { - // if we bottom out in ambiguity, create a type variable - // and a deferred predicate to resolve this when more type - // information is available. - - selcx - .infcx - .projection_ty_to_infer(param_env, projection_ty, cause, depth + 1, obligations) - .into() - }) + opt_normalize_projection_term(selcx, param_env, alias_term, cause.clone(), depth, obligations) + .ok() + .flatten() + .unwrap_or_else(move || { + // if we bottom out in ambiguity, create a type variable + // and a deferred predicate to resolve this when more type + // information is available. + + selcx + .infcx + .projection_term_to_infer(param_env, alias_term, cause, depth + 1, obligations) + .into() + }) } /// The guts of `normalize`: normalize a specific projection like `( /// often immediately appended to another obligations vector. So now this /// function takes an obligations vector and appends to it directly, which is /// slightly uglier but avoids the need for an extra short-lived allocation. +// FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, @@ -456,6 +452,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( /// an error for this obligation, but we legitimately should not, /// because it contains `[type error]`. Yuck! (See issue #29857 for /// one case where this arose.) +// FIXME(mgca): While this supports constants, it is only used for types by default right now fn normalize_to_error<'a, 'tcx>( selcx: &SelectionContext<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -469,9 +466,10 @@ fn normalize_to_error<'a, 'tcx>( | ty::AliasTermKind::InherentTy | ty::AliasTermKind::OpaqueTy | ty::AliasTermKind::FreeTy => selcx.infcx.next_ty_var(cause.span).into(), - ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { - selcx.infcx.next_const_var(cause.span).into() - } + ty::AliasTermKind::FreeConst + | ty::AliasTermKind::InherentConst + | ty::AliasTermKind::UnevaluatedConst + | ty::AliasTermKind::ProjectionConst => selcx.infcx.next_const_var(cause.span).into(), }; let mut obligations = PredicateObligations::new(); obligations.push(Obligation { @@ -484,36 +482,37 @@ fn normalize_to_error<'a, 'tcx>( } /// Confirm and normalize the given inherent projection. +// FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] pub fn normalize_inherent_projection<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, - alias_ty: ty::AliasTy<'tcx>, + alias_term: ty::AliasTerm<'tcx>, cause: ObligationCause<'tcx>, depth: usize, obligations: &mut PredicateObligations<'tcx>, -) -> Ty<'tcx> { +) -> ty::Term<'tcx> { let tcx = selcx.tcx(); if !tcx.recursion_limit().value_within_limit(depth) { // Halt compilation because it is important that overflows never be masked. tcx.dcx().emit_fatal(InherentProjectionNormalizationOverflow { span: cause.span, - ty: alias_ty.to_string(), + ty: alias_term.to_string(), }); } - let args = compute_inherent_assoc_ty_args( + let args = compute_inherent_assoc_term_args( selcx, param_env, - alias_ty, + alias_term, cause.clone(), depth, obligations, ); // Register the obligations arising from the impl and from the associated type itself. - let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, args); + let predicates = tcx.predicates_of(alias_term.def_id).instantiate(tcx, args); for (predicate, span) in predicates { let predicate = normalize_with_depth_to( selcx, @@ -531,7 +530,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( // cause code, inherent projections will be printed with identity instantiation in // diagnostics which is not ideal. // Consider creating separate cause codes for this specific situation. - ObligationCauseCode::WhereClause(alias_ty.def_id, span), + ObligationCauseCode::WhereClause(alias_term.def_id, span), ); obligations.push(Obligation::with_depth( @@ -543,27 +542,33 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( )); } - let ty = tcx.type_of(alias_ty.def_id).instantiate(tcx, args); + let term: Term<'tcx> = if alias_term.kind(tcx).is_type() { + tcx.type_of(alias_term.def_id).instantiate(tcx, args).into() + } else { + get_associated_const_value(selcx, alias_term.to_term(tcx).expect_const(), param_env).into() + }; - let mut ty = selcx.infcx.resolve_vars_if_possible(ty); - if ty.has_aliases() { - ty = normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, ty, obligations); + let mut term = selcx.infcx.resolve_vars_if_possible(term); + if term.has_aliases() { + term = + normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, term, obligations); } - ty + term } -pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>( +// FIXME(mgca): While this supports constants, it is only used for types by default right now +pub fn compute_inherent_assoc_term_args<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, - alias_ty: ty::AliasTy<'tcx>, + alias_term: ty::AliasTerm<'tcx>, cause: ObligationCause<'tcx>, depth: usize, obligations: &mut PredicateObligations<'tcx>, ) -> ty::GenericArgsRef<'tcx> { let tcx = selcx.tcx(); - let impl_def_id = tcx.parent(alias_ty.def_id); + let impl_def_id = tcx.parent(alias_term.def_id); let impl_args = selcx.infcx.fresh_args_for_item(cause.span, impl_def_id); let mut impl_ty = tcx.type_of(impl_def_id).instantiate(tcx, impl_args); @@ -580,7 +585,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>( // Infer the generic parameters of the impl by unifying the // impl type with the self type of the projection. - let mut self_ty = alias_ty.self_ty(); + let mut self_ty = alias_term.self_ty(); if !selcx.infcx.next_trait_solver() { self_ty = normalize_with_depth_to( selcx, @@ -602,7 +607,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>( } } - alias_ty.rebase_inherent_args_onto_impl(impl_args, tcx) + alias_term.rebase_inherent_args_onto_impl(impl_args, tcx) } enum Projected<'tcx> { @@ -630,6 +635,7 @@ impl<'tcx> Progress<'tcx> { /// /// IMPORTANT: /// - `obligation` must be fully normalized +// FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "info", skip(selcx))] fn project<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, @@ -896,7 +902,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( ImplSource::UserDefined(impl_data) => { // We have to be careful when projecting out of an // impl because of specialization. If we are not in - // codegen (i.e., projection mode is not "any"), and the + // codegen (i.e., `TypingMode` is not `PostAnalysis`), and the // impl's type is declared as default, then we disable // projection (even if the trait ref is fully // monomorphic). In the case where trait ref is not @@ -1189,6 +1195,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( }); } +// FIXME(mgca): While this supports constants, it is only used for types by default right now fn confirm_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, @@ -1222,6 +1229,7 @@ fn confirm_candidate<'cx, 'tcx>( result } +// FIXME(mgca): While this supports constants, it is only used for types by default right now fn confirm_select_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, @@ -1873,6 +1881,7 @@ fn confirm_async_fn_kind_helper_candidate<'cx, 'tcx>( .with_addl_obligations(nested) } +// FIXME(mgca): While this supports constants, it is only used for types by default right now fn confirm_param_env_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, @@ -1926,9 +1935,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( ) { Ok(InferOk { value: _, obligations }) => { nested_obligations.extend(obligations); - assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations); - // FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take - // a term instead. + assoc_term_own_obligations(selcx, obligation, &mut nested_obligations); Progress { term: cache_entry.term, obligations: nested_obligations } } Err(e) => { @@ -1942,6 +1949,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( } } +// FIXME(mgca): While this supports constants, it is only used for types by default right now fn confirm_impl_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, @@ -1955,8 +1963,8 @@ fn confirm_impl_candidate<'cx, 'tcx>( let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); let param_env = obligation.param_env; - let assoc_ty = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) { - Ok(assoc_ty) => assoc_ty, + let assoc_term = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) { + Ok(assoc_term) => assoc_term, Err(guar) => return Ok(Projected::Progress(Progress::error(tcx, guar))), }; @@ -1965,10 +1973,10 @@ fn confirm_impl_candidate<'cx, 'tcx>( // has impossible-to-satisfy predicates (since those were // allowed in ), // or because the impl is literally missing the definition. - if !assoc_ty.item.defaultness(tcx).has_value() { + if !assoc_term.item.defaultness(tcx).has_value() { debug!( "confirm_impl_candidate: no associated type {:?} for {:?}", - assoc_ty.item.name(), + assoc_term.item.name(), obligation.predicate ); if tcx.impl_self_is_guaranteed_unsized(impl_def_id) { @@ -1979,7 +1987,11 @@ fn confirm_impl_candidate<'cx, 'tcx>( return Ok(Projected::NoProgress(obligation.predicate.to_term(tcx))); } else { return Ok(Projected::Progress(Progress { - term: Ty::new_misc_error(tcx).into(), + term: if obligation.predicate.kind(tcx).is_type() { + Ty::new_misc_error(tcx).into() + } else { + ty::Const::new_misc_error(tcx).into() + }, obligations: nested, })); } @@ -1992,27 +2004,32 @@ fn confirm_impl_candidate<'cx, 'tcx>( // * `args` is `[u32]` // * `args` ends up as `[u32, S]` let args = obligation.predicate.args.rebase_onto(tcx, trait_def_id, args); - let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_ty.defining_node); - let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst); - - let term: ty::EarlyBinder<'tcx, ty::Term<'tcx>> = if is_const { - let did = assoc_ty.item.def_id; - let identity_args = crate::traits::GenericArgs::identity_for_item(tcx, did); - let uv = ty::UnevaluatedConst::new(did, identity_args); - ty::EarlyBinder::bind(ty::Const::new_unevaluated(tcx, uv).into()) + let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_term.defining_node); + + let term = if obligation.predicate.kind(tcx).is_type() { + tcx.type_of(assoc_term.item.def_id).map_bound(|ty| ty.into()) } else { - tcx.type_of(assoc_ty.item.def_id).map_bound(|ty| ty.into()) + ty::EarlyBinder::bind( + get_associated_const_value( + selcx, + obligation.predicate.to_term(tcx).expect_const(), + param_env, + ) + .into(), + ) }; - let progress = if !tcx.check_args_compatible(assoc_ty.item.def_id, args) { - let err = Ty::new_error_with_message( - tcx, - obligation.cause.span, - "impl item and trait item have different parameters", - ); - Progress { term: err.into(), obligations: nested } + let progress = if !tcx.check_args_compatible(assoc_term.item.def_id, args) { + let msg = "impl item and trait item have different parameters"; + let span = obligation.cause.span; + let err = if obligation.predicate.kind(tcx).is_type() { + Ty::new_error_with_message(tcx, span, msg).into() + } else { + ty::Const::new_error_with_message(tcx, span, msg).into() + }; + Progress { term: err, obligations: nested } } else { - assoc_ty_own_obligations(selcx, obligation, &mut nested); + assoc_term_own_obligations(selcx, obligation, &mut nested); Progress { term: term.instantiate(tcx, args), obligations: nested } }; Ok(Projected::Progress(progress)) @@ -2020,7 +2037,8 @@ fn confirm_impl_candidate<'cx, 'tcx>( // Get obligations corresponding to the predicates from the where-clause of the // associated type itself. -fn assoc_ty_own_obligations<'cx, 'tcx>( +// FIXME(mgca): While this supports constants, it is only used for types by default right now +fn assoc_term_own_obligations<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, nested: &mut PredicateObligations<'tcx>, @@ -2090,3 +2108,15 @@ impl<'cx, 'tcx> ProjectionCacheKeyExt<'cx, 'tcx> for ProjectionCacheKey<'tcx> { }) } } + +fn get_associated_const_value<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + alias_ct: ty::Const<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> ty::Const<'tcx> { + // FIXME(mgca): We shouldn't be invoking ctfe here, instead const items should be aliases to type + // system consts that we can retrieve with some `query const_arg_of_alias` query. Evaluating the + // constant is "close enough" to getting the actual rhs of the const item for now even if it might + // lead to some cycles + super::evaluate_const(selcx.infcx, alias_ct, param_env) +} diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 8008c7e4d342b..94190cd3ae33a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -406,7 +406,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let mut assume = predicate.trait_ref.args.const_at(2); - // FIXME(mgca): We should shallowly normalize this. if self.tcx().features().generic_const_exprs() { assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env) } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 2e32cda7602e4..08d3b92e9b5ef 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -6,6 +6,7 @@ use std::iter; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::lang_items::LangItem; use rustc_infer::traits::{ObligationCauseCode, PredicateObligations}; use rustc_middle::bug; @@ -486,7 +487,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { /// Pushes the obligations required for an inherent alias to be WF /// into `self.out`. // FIXME(inherent_associated_types): Merge this function with `fn compute_alias`. - fn add_wf_preds_for_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) { + fn add_wf_preds_for_inherent_projection(&mut self, data: ty::AliasTerm<'tcx>) { // An inherent projection is well-formed if // // (a) its predicates hold (*) @@ -498,7 +499,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { if !data.self_ty().has_escaping_bound_vars() { // FIXME(inherent_associated_types): Should this happen inside of a snapshot? // FIXME(inherent_associated_types): This is incompatible with the new solver and lazy norm! - let args = traits::project::compute_inherent_assoc_ty_args( + let args = traits::project::compute_inherent_assoc_term_args( &mut traits::SelectionContext::new(self.infcx), self.param_env, data, @@ -776,7 +777,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { self.out.extend(obligations); } ty::Alias(ty::Inherent, data) => { - self.add_wf_preds_for_inherent_projection(data); + self.add_wf_preds_for_inherent_projection(data.into()); return; // Subtree handled by compute_inherent_projection. } @@ -961,9 +962,6 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { match c.kind() { ty::ConstKind::Unevaluated(uv) => { if !c.has_escaping_bound_vars() { - let obligations = self.nominal_obligations(uv.def, uv.args); - self.out.extend(obligations); - let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( ty::ClauseKind::ConstEvaluatable(c), )); @@ -975,6 +973,16 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { self.param_env, predicate, )); + + if tcx.def_kind(uv.def) == DefKind::AssocConst + && tcx.def_kind(tcx.parent(uv.def)) == (DefKind::Impl { of_trait: false }) + { + self.add_wf_preds_for_inherent_projection(uv.into()); + return; // Subtree is handled by above function + } else { + let obligations = self.nominal_obligations(uv.def, uv.args); + self.out.extend(obligations); + } } } ty::ConstKind::Infer(_) => { diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 14a92ebb9f966..e52898cc6e242 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -32,8 +32,14 @@ fn normalize_canonicalized_projection_ty<'tcx>( let selcx = &mut SelectionContext::new(ocx.infcx); let cause = ObligationCause::dummy(); let mut obligations = PredicateObligations::new(); - let answer = - traits::normalize_projection_ty(selcx, param_env, goal, cause, 0, &mut obligations); + let answer = traits::normalize_projection_term( + selcx, + param_env, + goal.into(), + cause, + 0, + &mut obligations, + ); ocx.register_obligations(obligations); // #112047: With projections and opaques, we are able to create opaques that // are recursive (given some generic parameters of the opaque's type variables). @@ -104,14 +110,14 @@ fn normalize_canonicalized_inherent_projection_ty<'tcx>( let answer = traits::normalize_inherent_projection( selcx, param_env, - goal, + goal.into(), cause, 0, &mut obligations, ); ocx.register_obligations(obligations); - Ok(NormalizationResult { normalized_ty: answer }) + Ok(NormalizationResult { normalized_ty: answer.expect_type() }) }, ) } diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 0411c5c2325eb..b59495b93c836 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -474,10 +474,15 @@ pub enum AliasTermKind { /// Currently only used if the type alias references opaque types. /// Can always be normalized away. FreeTy, - /// An unevaluated const coming from a generic const expression. + + /// An unevaluated anonymous constants. UnevaluatedConst, /// An unevaluated const coming from an associated const. ProjectionConst, + /// A top level const item not part of a trait or impl. + FreeConst, + /// An associated const in an inherent `impl` + InherentConst, } impl AliasTermKind { @@ -486,11 +491,27 @@ impl AliasTermKind { AliasTermKind::ProjectionTy => "associated type", AliasTermKind::ProjectionConst => "associated const", AliasTermKind::InherentTy => "inherent associated type", + AliasTermKind::InherentConst => "inherent associated const", AliasTermKind::OpaqueTy => "opaque type", AliasTermKind::FreeTy => "type alias", + AliasTermKind::FreeConst => "unevaluated constant", AliasTermKind::UnevaluatedConst => "unevaluated constant", } } + + pub fn is_type(self) -> bool { + match self { + AliasTermKind::ProjectionTy + | AliasTermKind::InherentTy + | AliasTermKind::OpaqueTy + | AliasTermKind::FreeTy => true, + + AliasTermKind::UnevaluatedConst + | AliasTermKind::ProjectionConst + | AliasTermKind::InherentConst + | AliasTermKind::FreeConst => false, + } + } } impl From for AliasTermKind { @@ -566,7 +587,10 @@ impl AliasTerm { | AliasTermKind::InherentTy | AliasTermKind::OpaqueTy | AliasTermKind::FreeTy => {} - AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => { + AliasTermKind::InherentConst + | AliasTermKind::FreeConst + | AliasTermKind::UnevaluatedConst + | AliasTermKind::ProjectionConst => { panic!("Cannot turn `UnevaluatedConst` into `AliasTy`") } } @@ -603,18 +627,19 @@ impl AliasTerm { ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, ) .into(), - AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => { - I::Const::new_unevaluated( - interner, - ty::UnevaluatedConst::new(self.def_id, self.args), - ) - .into() - } + AliasTermKind::FreeConst + | AliasTermKind::InherentConst + | AliasTermKind::UnevaluatedConst + | AliasTermKind::ProjectionConst => I::Const::new_unevaluated( + interner, + ty::UnevaluatedConst::new(self.def_id, self.args), + ) + .into(), } } } -/// The following methods work only with (trait) associated type projections. +/// The following methods work only with (trait) associated term projections. impl AliasTerm { pub fn self_ty(self) -> I::Ty { self.args.type_at(0) @@ -659,6 +684,31 @@ impl AliasTerm { } } +/// The following methods work only with inherent associated term projections. +impl AliasTerm { + /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that. + /// + /// Does the following transformation: + /// + /// ```text + /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m] + /// + /// I_i impl args + /// P_j GAT args + /// ``` + pub fn rebase_inherent_args_onto_impl( + self, + impl_args: I::GenericArgs, + interner: I, + ) -> I::GenericArgs { + debug_assert!(matches!( + self.kind(interner), + AliasTermKind::InherentTy | AliasTermKind::InherentConst + )); + interner.mk_args_from_iter(impl_args.iter().chain(self.args.iter().skip(1))) + } +} + impl From> for AliasTerm { fn from(ty: ty::AliasTy) -> Self { AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () } diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index c80a567117c66..e3c4a793b37f6 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -273,8 +273,10 @@ impl Relate for ty::AliasTerm { false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle )?, ty::AliasTermKind::ProjectionTy + | ty::AliasTermKind::FreeConst | ty::AliasTermKind::FreeTy | ty::AliasTermKind::InherentTy + | ty::AliasTermKind::InherentConst | ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { relate_args_invariantly(relation, a.args, b.args)? diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 21adbffc02743..cf2e4284d10da 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -514,28 +514,6 @@ impl AliasTy { } } -/// The following methods work only with inherent associated type projections. -impl AliasTy { - /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that. - /// - /// Does the following transformation: - /// - /// ```text - /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m] - /// - /// I_i impl args - /// P_j GAT args - /// ``` - pub fn rebase_inherent_args_onto_impl( - self, - impl_args: I::GenericArgs, - interner: I, - ) -> I::GenericArgs { - debug_assert_eq!(self.kind(interner), AliasTyKind::Inherent); - interner.mk_args_from_iter(impl_args.iter().chain(self.args.iter().skip(1))) - } -} - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr( feature = "nightly", diff --git a/tests/crashes/127643.rs b/tests/crashes/127643.rs index a4db9397bdefa..b5ec58b70e936 100644 --- a/tests/crashes/127643.rs +++ b/tests/crashes/127643.rs @@ -1,18 +1,18 @@ //@ known-bug: #127643 -#![feature(associated_const_equality)] +#![feature(generic_const_items, associated_const_equality)] +#![expect(incomplete_features)] -fn user() -> impl Owner {} - -trait Owner { - const C: K; -} -impl Owner for () { - const C: K = K::DEFAULT; +trait Foo { + const ASSOC: u32; } -trait ConstDefault { - const DEFAULT: Self; +impl Foo for () { + const ASSOC: u32 = N; } -fn main() {} +fn bar = { N }>>() {} + +fn main() { + bar::<10_u64, ()>(); +} diff --git a/tests/crashes/133066.rs b/tests/crashes/133066.rs deleted file mode 100644 index 732ebb7079fd0..0000000000000 --- a/tests/crashes/133066.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #133066 -trait Owner { - const C: u32; -} - -impl Owner for () {;} - -fn take0(_: impl Owner = { N }>) {} - -fn main() { - take0::(()); -} diff --git a/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr b/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr index a05aaf2af649e..1aac357d60e43 100644 --- a/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr +++ b/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr @@ -39,14 +39,6 @@ error: unconstrained generic constant LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: required by a bound in `test1` - --> $DIR/auxiliary/const_evaluatable_lib.rs:5:10 - | -LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] - | ----- required by a bound in this function -LL | where -LL | [u8; std::mem::size_of::() - 1]: Sized, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1` help: try adding a `where` bound | LL | fn user() where [(); std::mem::size_of::() - 1]: { @@ -59,10 +51,13 @@ LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required by a bound in `test1` - --> $DIR/auxiliary/const_evaluatable_lib.rs:3:27 + --> $DIR/auxiliary/const_evaluatable_lib.rs:5:10 | LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1` + | ----- required by a bound in this function +LL | where +LL | [u8; std::mem::size_of::() - 1]: Sized, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1` help: try adding a `where` bound | LL | fn user() where [(); std::mem::size_of::() - 1]: {