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 706b56114d05e..78f6386cd6b34 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -3031,7 +3031,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, ) -> Result<(), ErrorGuaranteed> { let tcx = self.tcx(); - if tcx.is_type_const(def_id) { + // FIXME(gca): Intentionally disallowing paths to inherent associated non-type constants + // until a refactoring for how generic args for IACs are represented has been landed. + let is_inherent_assoc_const = tcx.def_kind(def_id) + == DefKind::AssocConst { is_type_const: false } + && tcx.def_kind(tcx.parent(def_id)) == DefKind::Impl { of_trait: false }; + if tcx.is_type_const(def_id) + || tcx.features().generic_const_args() && !is_inherent_assoc_const + { Ok(()) } else { let mut err = self.dcx().struct_span_err( diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 0229af53f2a67..5b4c5347564ab 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -188,7 +188,7 @@ impl<'tcx> InferCtxt<'tcx> { bug!("generalized `{source_term:?} to infer, not an alias"); }; match source_alias.kind(self.tcx) { - ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { + ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst { .. } => { // FIXME: This does not handle subtyping correctly, we could // instead create a new inference variable `?normalized_source`, emitting // `Projection(normalized_source, ?ty_normalized)` and @@ -204,8 +204,8 @@ impl<'tcx> InferCtxt<'tcx> { | ty::AliasTermKind::OpaqueTy => { return Err(TypeError::CyclicTy(source_term.expect_type())); } - ty::AliasTermKind::InherentConst - | ty::AliasTermKind::FreeConst + ty::AliasTermKind::InherentConst { .. } + | ty::AliasTermKind::FreeConst { .. } | ty::AliasTermKind::UnevaluatedConst => { return Err(TypeError::CyclicConst(source_term.expect_const())); } diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 9913261b14d95..a4730b8f24c48 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -212,17 +212,17 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ty::AliasTermKind::ProjectionTy } } - DefKind::AssocConst { .. } => { + DefKind::AssocConst { is_type_const } => { if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id)) { - ty::AliasTermKind::InherentConst + ty::AliasTermKind::InherentConst { is_type_const } } else { - ty::AliasTermKind::ProjectionConst + ty::AliasTermKind::ProjectionConst { is_type_const } } } DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy, DefKind::TyAlias => ty::AliasTermKind::FreeTy, - DefKind::Const { .. } => ty::AliasTermKind::FreeConst, + DefKind::Const { is_type_const } => ty::AliasTermKind::FreeConst { is_type_const }, DefKind::AnonConst | DefKind::Ctor(_, CtorKind::Const) => { ty::AliasTermKind::UnevaluatedConst } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 1262974325a1f..aa7be1e700f1e 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3152,7 +3152,7 @@ define_print! { ty::AliasTerm<'tcx> { match self.kind(p.tcx()) { - ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => p.pretty_print_inherent_projection(*self)?, + ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst { .. } => p.pretty_print_inherent_projection(*self)?, ty::AliasTermKind::ProjectionTy => { if !(p.should_print_verbose() || with_reduced_queries()) && p.tcx().is_impl_trait_in_trait(self.def_id) @@ -3163,10 +3163,10 @@ define_print! { } } ty::AliasTermKind::FreeTy - | ty::AliasTermKind::FreeConst + | ty::AliasTermKind::FreeConst { .. } | ty::AliasTermKind::OpaqueTy | ty::AliasTermKind::UnevaluatedConst - | ty::AliasTermKind::ProjectionConst => { + | ty::AliasTermKind::ProjectionConst { .. } => { p.print_def_path(self.def_id, self.args)?; } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 95f75b473bf82..0b0b1c5d03b59 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -948,11 +948,11 @@ impl<'tcx> TyCtxt<'tcx> { } ty::AliasTermKind::OpaqueTy => Some(self.variances_of(def_id)), ty::AliasTermKind::InherentTy - | ty::AliasTermKind::InherentConst + | ty::AliasTermKind::InherentConst { .. } | ty::AliasTermKind::FreeTy - | ty::AliasTermKind::FreeConst + | ty::AliasTermKind::FreeConst { .. } | ty::AliasTermKind::UnevaluatedConst - | ty::AliasTermKind::ProjectionConst => None, + | ty::AliasTermKind::ProjectionConst { .. } => None, } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs index 46312be5ea9a9..ed977c1dc9167 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs @@ -14,13 +14,8 @@ where &mut self, goal: Goal>, ) -> QueryResult { - if let Some(normalized_const) = self.evaluate_const( - goal.param_env, - ty::UnevaluatedConst::new( - goal.predicate.alias.def_id.try_into().unwrap(), - goal.predicate.alias.args, - ), - ) { + let uv = goal.predicate.alias.expect_ct(self.cx()); + if let Some(normalized_const) = self.evaluate_const(goal.param_env, uv) { self.instantiate_normalizes_to_term(goal, normalized_const.into()); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { 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 8777f84957a79..f049c34d956e8 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 @@ -29,10 +29,24 @@ where .map(|pred| goal.with(cx, pred)), ); - let actual = if free_alias.kind(cx).is_type() { - cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args).into() - } else { - cx.const_of_item(free_alias.def_id).instantiate(cx, free_alias.args).into() + let actual = match free_alias.kind(cx) { + ty::AliasTermKind::FreeTy => { + cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args).into() + } + ty::AliasTermKind::FreeConst { is_type_const: true } => { + cx.const_of_item(free_alias.def_id).instantiate(cx, free_alias.args).into() + } + ty::AliasTermKind::FreeConst { is_type_const: false } => { + if let Some(normalized_const) = + self.evaluate_const(goal.param_env, free_alias.expect_ct(cx)) + { + normalized_const.into() + } else { + return self + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + } + } + kind => panic!("expected free alias, found {kind:?}"), }; self.instantiate_normalizes_to_term(goal, actual); 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 42aa237762d9e..275388f7da8e3 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 @@ -51,10 +51,23 @@ where .map(|pred| goal.with(cx, pred)), ); - let normalized = if inherent.kind(cx).is_type() { - cx.type_of(inherent.def_id).instantiate(cx, inherent_args).into() - } else { - cx.const_of_item(inherent.def_id).instantiate(cx, inherent_args).into() + let normalized = match inherent.kind(cx) { + ty::AliasTermKind::InherentTy => { + cx.type_of(inherent.def_id).instantiate(cx, inherent_args).into() + } + ty::AliasTermKind::InherentConst { is_type_const: true } => { + cx.const_of_item(inherent.def_id).instantiate(cx, inherent_args).into() + } + ty::AliasTermKind::InherentConst { is_type_const: false } => { + // FIXME(gca): This is dead code at the moment. It should eventually call + // self.evaluate_const like projected consts do in consider_impl_candidate in + // normalizes_to/mod.rs. However, how generic args are represented for IACs is up in + // the air right now. + // Will self.evaluate_const eventually take the inherent_args or the impl_args form + // of args? It might be either. + panic!("References to inherent associated consts should have been blocked"); + } + kind => panic!("expected inherent alias, found {kind:?}"), }; 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 4deb6ed0bb81f..2dd6c268ef005 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 @@ -32,7 +32,7 @@ where debug_assert!(self.term_is_fully_unconstrained(goal)); let cx = self.cx(); match goal.predicate.alias.kind(cx) { - ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { + ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst { .. } => { let trait_ref = goal.predicate.alias.trait_ref(cx); let (_, proven_via) = self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| { @@ -83,11 +83,11 @@ where }, ) } - ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => { + ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst { .. } => { self.normalize_inherent_associated_term(goal) } ty::AliasTermKind::OpaqueTy => self.normalize_opaque_type(goal), - ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst => { + ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst { .. } => { self.normalize_free_alias(goal) } ty::AliasTermKind::UnevaluatedConst => self.normalize_anon_const(goal), @@ -264,7 +264,7 @@ where let error_response = |ecx: &mut EvalCtxt<'_, D>, guar| { let error_term = match goal.predicate.alias.kind(cx) { ty::AliasTermKind::ProjectionTy => Ty::new_error(cx, guar).into(), - ty::AliasTermKind::ProjectionConst => Const::new_error(cx, guar).into(), + ty::AliasTermKind::ProjectionConst { .. } => Const::new_error(cx, guar).into(), kind => panic!("expected projection, found {kind:?}"), }; ecx.instantiate_normalizes_to_term(goal, error_term); @@ -380,15 +380,28 @@ where // Finally we construct the actual value of the associated type. let term = match goal.predicate.alias.kind(cx) { ty::AliasTermKind::ProjectionTy => { - cx.type_of(target_item_def_id).map_bound(|ty| ty.into()) + cx.type_of(target_item_def_id).instantiate(cx, target_args).into() } - ty::AliasTermKind::ProjectionConst => { - cx.const_of_item(target_item_def_id).map_bound(|ct| ct.into()) + ty::AliasTermKind::ProjectionConst { is_type_const: true } => { + cx.const_of_item(target_item_def_id).instantiate(cx, target_args).into() + } + ty::AliasTermKind::ProjectionConst { is_type_const: false } => { + let uv = ty::UnevaluatedConst::new( + target_item_def_id.try_into().unwrap(), + target_args, + ); + if let Some(eval) = ecx.evaluate_const(goal.param_env, uv) { + eval.into() + } else { + return ecx.evaluate_added_goals_and_make_canonical_response( + Certainty::AMBIGUOUS, + ); + } } kind => panic!("expected projection, found {kind:?}"), }; - ecx.instantiate_normalizes_to_term(goal, term.instantiate(cx, target_args)); + ecx.instantiate_normalizes_to_term(goal, term); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 04c9edc25d172..a1ffecc6311bb 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1588,7 +1588,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; if let Some(lhs) = lhs.to_alias_term() - && let ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst = lhs.kind(self.tcx) + && let ty::AliasTermKind::ProjectionTy + | ty::AliasTermKind::ProjectionConst { .. } = lhs.kind(self.tcx) && let Some((better_type_err, expected_term)) = derive_better_type_error(lhs, rhs) { @@ -1597,7 +1598,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { better_type_err, ) } else if let Some(rhs) = rhs.to_alias_term() - && let ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst = rhs.kind(self.tcx) + && let ty::AliasTermKind::ProjectionTy + | ty::AliasTermKind::ProjectionConst { .. } = rhs.kind(self.tcx) && let Some((better_type_err, expected_term)) = derive_better_type_error(rhs, lhs) { diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 77834320dbc6b..fadd3a9f73162 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -388,8 +388,8 @@ impl<'tcx> BestObligation<'tcx> { self.detect_error_in_self_ty_normalization(goal, pred.self_ty())?; } Some(ty::PredicateKind::NormalizesTo(pred)) - if let ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst = - pred.alias.kind(tcx) => + if let ty::AliasTermKind::ProjectionTy + | ty::AliasTermKind::ProjectionConst { .. } = pred.alias.kind(tcx) => { self.detect_error_in_self_ty_normalization(goal, pred.alias.self_ty())?; self.detect_non_well_formed_assoc_item(goal, pred.alias)?; @@ -450,7 +450,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { ty::PredicateKind::NormalizesTo(normalizes_to) if matches!( normalizes_to.alias.kind(tcx), - ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst + ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst { .. } ) => { ChildMode::Trait(pred.kind().rebind(ty::TraitPredicate { diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 65c4b40d43964..3ef8ab71dfb77 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -331,15 +331,24 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { ), ); 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 { - infcx + let res = match free.kind(infcx.tcx) { + ty::AliasTermKind::FreeTy => infcx + .tcx + .type_of(free.def_id) + .instantiate(infcx.tcx, free.args) + .fold_with(self) + .into(), + ty::AliasTermKind::FreeConst { is_type_const: true } => infcx .tcx .const_of_item(free.def_id) .instantiate(infcx.tcx, free.args) .fold_with(self) - .into() + .into(), + ty::AliasTermKind::FreeConst { is_type_const: false } => { + super::evaluate_const(infcx, free.to_term(infcx.tcx).expect_const(), self.param_env) + .into() + } + kind => panic!("expected free alias, found {kind:?}"), }; self.depth -= 1; res diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 72d3ba9629f4d..7f613c52a7a94 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -467,10 +467,12 @@ 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::FreeConst - | ty::AliasTermKind::InherentConst + ty::AliasTermKind::FreeConst { .. } + | ty::AliasTermKind::InherentConst { .. } | ty::AliasTermKind::UnevaluatedConst - | ty::AliasTermKind::ProjectionConst => selcx.infcx.next_const_var(cause.span).into(), + | ty::AliasTermKind::ProjectionConst { .. } => { + selcx.infcx.next_const_var(cause.span).into() + } }; let mut obligations = PredicateObligations::new(); obligations.push(Obligation { @@ -543,10 +545,22 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( )); } - let term: Term<'tcx> = if alias_term.kind(tcx).is_type() { - tcx.type_of(alias_term.def_id).instantiate(tcx, args).into() - } else { - tcx.const_of_item(alias_term.def_id).instantiate(tcx, args).into() + let term: Term<'tcx> = match alias_term.kind(tcx) { + ty::AliasTermKind::InherentTy => { + tcx.type_of(alias_term.def_id).instantiate(tcx, args).into() + } + ty::AliasTermKind::InherentConst { is_type_const: true } => { + tcx.const_of_item(alias_term.def_id).instantiate(tcx, args).into() + } + ty::AliasTermKind::InherentConst { is_type_const: false } => { + // FIXME(gca): This is dead code at the moment. It should eventually call + // super::evaluate_const like projected consts do in confirm_impl_candidate in this + // file. However, how generic args are represented for IACs is up in the air right now. + // Will super::evaluate_const eventually take the inherent_args or the impl_args form of + // args? It might be either. + panic!("References to inherent associated consts should have been blocked"); + } + kind => panic!("expected inherent alias, found {kind:?}"), }; let mut term = selcx.infcx.resolve_vars_if_possible(term); @@ -2044,12 +2058,6 @@ fn confirm_impl_candidate<'cx, 'tcx>( 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_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.const_of_item(assoc_term.item.def_id).map_bound(|ct| ct.into()) - }; - 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; @@ -2061,7 +2069,23 @@ fn confirm_impl_candidate<'cx, 'tcx>( Progress { term: err, obligations: nested } } else { assoc_term_own_obligations(selcx, obligation, &mut nested); - Progress { term: term.instantiate(tcx, args), obligations: nested } + + let term = match obligation.predicate.kind(tcx) { + ty::AliasTermKind::ProjectionTy => { + tcx.type_of(assoc_term.item.def_id).instantiate(tcx, args).into() + } + ty::AliasTermKind::ProjectionConst { is_type_const: true } => { + tcx.const_of_item(assoc_term.item.def_id).instantiate(tcx, args).into() + } + ty::AliasTermKind::ProjectionConst { is_type_const: false } => { + let uv = ty::UnevaluatedConst::new(assoc_term.item.def_id, args); + let ct = ty::Const::new_unevaluated(tcx, uv); + super::evaluate_const(selcx.infcx, ct, param_env).into() + } + kind => panic!("expected projection alias, found {kind:?}"), + }; + + Progress { term, obligations: nested } }; Ok(Projected::Progress(progress)) } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index a088384146293..76324be2eb37a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -326,13 +326,13 @@ impl<'a, 'tcx> QueryNormalizer<'a, 'tcx> { debug!("QueryNormalizer: c_term = {:#?}", c_term); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); let result = match term.kind(tcx) { - ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { + ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst { .. } => { tcx.normalize_canonicalized_projection(c_term) } - ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst => { + ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst { .. } => { tcx.normalize_canonicalized_free_alias(c_term) } - ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => { + ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst { .. } => { tcx.normalize_canonicalized_inherent_projection(c_term) } kind @ (ty::AliasTermKind::OpaqueTy | ty::AliasTermKind::UnevaluatedConst) => { @@ -379,7 +379,7 @@ impl<'a, 'tcx> QueryNormalizer<'a, 'tcx> { && (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || matches!( term.kind(tcx), - ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst + ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst { .. } )) { res.try_fold_with(self) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 377505ee5f0d2..8406e816948ef 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1059,7 +1059,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { ty::ConstKind::Unevaluated(uv) => { if !c.has_escaping_bound_vars() { // Skip type consts as mGCA doesn't support evaluatable clauses - if !tcx.is_type_const(uv.def) { + if !tcx.is_type_const(uv.def) && !tcx.features().generic_const_args() { let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( ty::ClauseKind::ConstEvaluatable(c), )); diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 5277e0a992fcd..4e92239d31377 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -518,23 +518,28 @@ pub enum AliasTermKind { /// An unevaluated anonymous constants. UnevaluatedConst, /// An unevaluated const coming from an associated const. - ProjectionConst, + ProjectionConst { is_type_const: bool }, /// A top level const item not part of a trait or impl. - FreeConst, + FreeConst { is_type_const: bool }, /// An associated const in an inherent `impl` - InherentConst, + InherentConst { is_type_const: bool }, } impl AliasTermKind { pub fn descr(self) -> &'static str { match self { AliasTermKind::ProjectionTy => "associated type", - AliasTermKind::ProjectionConst => "associated const", + AliasTermKind::ProjectionConst { is_type_const: true } => "associated constant", + AliasTermKind::ProjectionConst { is_type_const: false } => "associated type constant", AliasTermKind::InherentTy => "inherent associated type", - AliasTermKind::InherentConst => "inherent associated const", + AliasTermKind::InherentConst { is_type_const: true } => { + "inherent associated type constant" + } + AliasTermKind::InherentConst { is_type_const: false } => "inherent associated constant", AliasTermKind::OpaqueTy => "opaque type", AliasTermKind::FreeTy => "type alias", - AliasTermKind::FreeConst => "unevaluated constant", + AliasTermKind::FreeConst { is_type_const: true } => "free type constant", + AliasTermKind::FreeConst { is_type_const: false } => "free constant", AliasTermKind::UnevaluatedConst => "unevaluated constant", } } @@ -547,9 +552,9 @@ impl AliasTermKind { | AliasTermKind::FreeTy => true, AliasTermKind::UnevaluatedConst - | AliasTermKind::ProjectionConst - | AliasTermKind::InherentConst - | AliasTermKind::FreeConst => false, + | AliasTermKind::ProjectionConst { .. } + | AliasTermKind::InherentConst { .. } + | AliasTermKind::FreeConst { .. } => false, } } } @@ -629,26 +634,42 @@ impl AliasTerm { AliasTermKind::InherentTy => AliasTyKind::Inherent { def_id: self.def_id }, AliasTermKind::OpaqueTy => AliasTyKind::Opaque { def_id: self.def_id }, AliasTermKind::FreeTy => AliasTyKind::Free { def_id: self.def_id }, - AliasTermKind::InherentConst - | AliasTermKind::FreeConst + kind @ (AliasTermKind::InherentConst { .. } + | AliasTermKind::FreeConst { .. } | AliasTermKind::UnevaluatedConst - | AliasTermKind::ProjectionConst => { - panic!("Cannot turn `UnevaluatedConst` into `AliasTy`") + | AliasTermKind::ProjectionConst { .. }) => { + panic!("Cannot turn `{}` into `AliasTy`", kind.descr()) } }; ty::AliasTy { kind, args: self.args, _use_alias_ty_new_instead: () } } + pub fn expect_ct(self, interner: I) -> ty::UnevaluatedConst { + match self.kind(interner) { + AliasTermKind::InherentConst { .. } + | AliasTermKind::FreeConst { .. } + | AliasTermKind::UnevaluatedConst + | AliasTermKind::ProjectionConst { .. } => {} + kind @ (AliasTermKind::ProjectionTy + | AliasTermKind::InherentTy + | AliasTermKind::OpaqueTy + | AliasTermKind::FreeTy) => { + panic!("Cannot turn `{}` into `UnevaluatedConst`", kind.descr()) + } + } + ty::UnevaluatedConst { def: self.def_id.try_into().unwrap(), args: self.args } + } + pub fn kind(self, interner: I) -> AliasTermKind { interner.alias_term_kind(self) } pub fn to_term(self, interner: I) -> I::Term { let alias_ty_kind = match self.kind(interner) { - AliasTermKind::FreeConst - | AliasTermKind::InherentConst + AliasTermKind::FreeConst { .. } + | AliasTermKind::InherentConst { .. } | AliasTermKind::UnevaluatedConst - | AliasTermKind::ProjectionConst => { + | AliasTermKind::ProjectionConst { .. } => { return I::Const::new_unevaluated( interner, ty::UnevaluatedConst::new(self.def_id.try_into().unwrap(), self.args), @@ -685,7 +706,7 @@ impl AliasTerm { assert!( matches!( self.kind(interner), - AliasTermKind::ProjectionTy | AliasTermKind::ProjectionConst + AliasTermKind::ProjectionTy | AliasTermKind::ProjectionConst { .. } ), "expected a projection" ); @@ -738,7 +759,7 @@ impl AliasTerm { ) -> I::GenericArgs { debug_assert!(matches!( self.kind(interner), - AliasTermKind::InherentTy | AliasTermKind::InherentConst + AliasTermKind::InherentTy | AliasTermKind::InherentConst { .. } )); interner.mk_args_from_iter(impl_args.iter().chain(self.args.iter().skip(1))) } diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 61095a00d0414..3a4c563d78e25 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -249,12 +249,12 @@ impl Relate for ty::AliasTerm { b.args, )?, ty::AliasTermKind::ProjectionTy - | ty::AliasTermKind::FreeConst + | ty::AliasTermKind::FreeConst { .. } | ty::AliasTermKind::FreeTy | ty::AliasTermKind::InherentTy - | ty::AliasTermKind::InherentConst + | ty::AliasTermKind::InherentConst { .. } | ty::AliasTermKind::UnevaluatedConst - | ty::AliasTermKind::ProjectionConst => { + | ty::AliasTermKind::ProjectionConst { .. } => { relate_args_invariantly(relation, a.args, b.args)? } }; diff --git a/tests/ui/const-generics/gca/path-to-non-type-const.rs b/tests/ui/const-generics/gca/path-to-non-type-const.rs new file mode 100644 index 0000000000000..f5bdeebb3c88e --- /dev/null +++ b/tests/ui/const-generics/gca/path-to-non-type-const.rs @@ -0,0 +1,36 @@ +//@ check-pass +//@ revisions: old next +//@[next] compile-flags: -Znext-solver + +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +#![expect(incomplete_features)] + +trait Trait { + const PROJECTED: usize; +} + +struct StructImpl; +struct GenericStructImpl; + +const FREE: usize = 1; + +impl Trait for StructImpl { + const PROJECTED: usize = 1; +} + +impl Trait for GenericStructImpl { + const PROJECTED: usize = A; +} + +struct Struct; + +fn f() { + let _ = Struct::<{ T::PROJECTED }>; +} + +fn main() { + let _ = Struct::; + let _ = Struct::<{ ::PROJECTED }>; + let _ = Struct::<{ as Trait>::PROJECTED }>; +} diff --git a/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.next.stderr b/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.next.stderr new file mode 100644 index 0000000000000..df4be9bb17c76 --- /dev/null +++ b/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.next.stderr @@ -0,0 +1,24 @@ +error: use of `const` in the type system not defined as `type const` + --> $DIR/path-to-non-type-inherent-associated-const.rs:25:24 + | +LL | let _ = Struct::<{ StructImpl::INHERENT }>; + | ^^^^^^^^^^^^^^^^^^^^ + | +help: add `type` before `const` for `StructImpl::INHERENT` + | +LL | type const INHERENT: usize = 1; + | ++++ + +error: use of `const` in the type system not defined as `type const` + --> $DIR/path-to-non-type-inherent-associated-const.rs:27:24 + | +LL | let _ = Struct::<{ GenericStructImpl::<2>::INHERENT }>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add `type` before `const` for `GenericStructImpl::::INHERENT` + | +LL | type const INHERENT: usize = A; + | ++++ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.old.stderr b/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.old.stderr new file mode 100644 index 0000000000000..df4be9bb17c76 --- /dev/null +++ b/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.old.stderr @@ -0,0 +1,24 @@ +error: use of `const` in the type system not defined as `type const` + --> $DIR/path-to-non-type-inherent-associated-const.rs:25:24 + | +LL | let _ = Struct::<{ StructImpl::INHERENT }>; + | ^^^^^^^^^^^^^^^^^^^^ + | +help: add `type` before `const` for `StructImpl::INHERENT` + | +LL | type const INHERENT: usize = 1; + | ++++ + +error: use of `const` in the type system not defined as `type const` + --> $DIR/path-to-non-type-inherent-associated-const.rs:27:24 + | +LL | let _ = Struct::<{ GenericStructImpl::<2>::INHERENT }>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add `type` before `const` for `GenericStructImpl::::INHERENT` + | +LL | type const INHERENT: usize = A; + | ++++ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.rs b/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.rs new file mode 100644 index 0000000000000..819fd74b9f121 --- /dev/null +++ b/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.rs @@ -0,0 +1,29 @@ +//! This test should be part of path-to-non-type-const.rs, and should pass. However, we are holding +//! off on implementing paths to IACs until a refactoring of how IAC generics are represented. +//@ revisions: old next +//@[next] compile-flags: -Znext-solver + +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +struct StructImpl; +struct GenericStructImpl; + +impl StructImpl { + const INHERENT: usize = 1; +} + +impl GenericStructImpl { + const INHERENT: usize = A; +} + +struct Struct; + +fn main() { + let _ = Struct::<{ StructImpl::INHERENT }>; + //~^ ERROR use of `const` in the type system not defined as `type const` + let _ = Struct::<{ GenericStructImpl::<2>::INHERENT }>; + //~^ ERROR use of `const` in the type system not defined as `type const` +} diff --git a/tests/ui/const-generics/mgca/cyclic-type-const-151251.rs b/tests/ui/const-generics/mgca/cyclic-type-const-151251.rs index a7e46ad877e72..28efaa8df830a 100644 --- a/tests/ui/const-generics/mgca/cyclic-type-const-151251.rs +++ b/tests/ui/const-generics/mgca/cyclic-type-const-151251.rs @@ -5,6 +5,6 @@ #![expect(incomplete_features)] type const A: u8 = A; -//~^ ERROR overflow normalizing the unevaluated constant `A` +//~^ ERROR overflow normalizing the free type constant `A` fn main() {} diff --git a/tests/ui/const-generics/mgca/cyclic-type-const-151251.stderr b/tests/ui/const-generics/mgca/cyclic-type-const-151251.stderr index 47653dd1896f7..fea5c6695f91e 100644 --- a/tests/ui/const-generics/mgca/cyclic-type-const-151251.stderr +++ b/tests/ui/const-generics/mgca/cyclic-type-const-151251.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow normalizing the unevaluated constant `A` +error[E0275]: overflow normalizing the free type constant `A` --> $DIR/cyclic-type-const-151251.rs:7:1 | LL | type const A: u8 = A; diff --git a/tests/ui/const-generics/mgca/type_const-recursive.rs b/tests/ui/const-generics/mgca/type_const-recursive.rs index ebaab51bbc3b6..39680c39f55b2 100644 --- a/tests/ui/const-generics/mgca/type_const-recursive.rs +++ b/tests/ui/const-generics/mgca/type_const-recursive.rs @@ -3,6 +3,6 @@ type const A: u8 = A; -//~^ ERROR: overflow normalizing the unevaluated constant `A` [E0275] +//~^ ERROR: overflow normalizing the free type constant `A` [E0275] fn main() {} diff --git a/tests/ui/const-generics/mgca/type_const-recursive.stderr b/tests/ui/const-generics/mgca/type_const-recursive.stderr index d21ccb22bc90b..00ac1dfc7f0e3 100644 --- a/tests/ui/const-generics/mgca/type_const-recursive.stderr +++ b/tests/ui/const-generics/mgca/type_const-recursive.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow normalizing the unevaluated constant `A` +error[E0275]: overflow normalizing the free type constant `A` --> $DIR/type_const-recursive.rs:5:1 | LL | type const A: u8 = A;