From ec036cda3fee341d938336b64bc38cd11df7231d Mon Sep 17 00:00:00 2001 From: Boxy Date: Sat, 30 Nov 2024 19:31:06 +0000 Subject: [PATCH 1/2] Don't try and handle unfed `type_of` on anon consts --- compiler/rustc_hir_analysis/src/collect.rs | 5 +- .../rustc_hir_analysis/src/collect/type_of.rs | 243 +----------------- .../coroutine-in-orphaned-anon-const.rs | 2 - .../coroutine-in-orphaned-anon-const.stderr | 10 +- .../bound/unknown-assoc-with-const-arg.rs | 2 - .../bound/unknown-assoc-with-const-arg.stderr | 22 +- 6 files changed, 14 insertions(+), 270 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 8d5824130d858..a4636da3f6213 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -309,10 +309,10 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { self.tcx.ensure().type_of(param.def_id); if let Some(default) = default { // need to store default and type of default + self.tcx.ensure().const_param_default(param.def_id); if let hir::ConstArgKind::Anon(ac) = default.kind { self.tcx.ensure().type_of(ac.def_id); } - self.tcx.ensure().const_param_default(param.def_id); } } } @@ -1817,7 +1817,6 @@ fn const_param_default<'tcx>( ), }; let icx = ItemCtxt::new(tcx, def_id); - // FIXME(const_generics): investigate which places do and don't need const ty feeding - let ct = icx.lowerer().lower_const_arg(default_ct, FeedConstTy::No); + let ct = icx.lowerer().lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id())); ty::EarlyBinder::bind(ct) } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 7cf99bebd36a3..72d5b3ac4f5e2 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -12,7 +12,6 @@ use rustc_middle::ty::{self, Article, IsSuggestable, Ty, TyCtxt, TypeVisitableEx use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Ident; use rustc_span::{DUMMY_SP, Span}; -use tracing::debug; use super::{ItemCtxt, bad_placeholder}; use crate::errors::TypeofReservedKeywordUsed; @@ -138,252 +137,26 @@ fn const_arg_anon_type_of<'tcx>(tcx: TyCtxt<'tcx>, arg_hir_id: HirId, span: Span use hir::*; use rustc_middle::ty::Ty; - let parent_node_id = tcx.parent_hir_id(arg_hir_id); - let parent_node = tcx.hir_node(parent_node_id); - - let (generics, arg_idx) = match parent_node { - // Easy case: arrays repeat expressions. + match tcx.parent_hir_node(arg_hir_id) { + // Array length const arguments do not have `type_of` fed as there is never a corresponding + // generic parameter definition. Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. }) | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) if constant.hir_id == arg_hir_id => { return tcx.types.usize; } - Node::GenericParam(&GenericParam { - def_id: param_def_id, - kind: GenericParamKind::Const { default: Some(ct), .. }, - .. - }) if ct.hir_id == arg_hir_id => { - return tcx - .type_of(param_def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"); - } - - // This match arm is for when the def_id appears in a GAT whose - // path can't be resolved without typechecking e.g. - // - // trait Foo { - // type Assoc; - // fn foo() -> Self::Assoc<3>; - // } - // - // In the above code we would call this query with the def_id of 3 and - // the parent_node we match on would be the hir node for Self::Assoc<3> - // - // `Self::Assoc<3>` cant be resolved without typechecking here as we - // didnt write ::Assoc<3>. If we did then another match - // arm would handle this. - // - // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU - Node::Ty(hir_ty @ hir::Ty { kind: TyKind::Path(QPath::TypeRelative(ty, segment)), .. }) => { - // Find the Item containing the associated type so we can create an ItemCtxt. - // Using the ItemCtxt lower the HIR for the unresolved assoc type into a - // ty which is a fully resolved projection. - // For the code example above, this would mean lowering `Self::Assoc<3>` - // to a ty::Alias(ty::Projection, `::Assoc<3>`). - let item_def_id = tcx.hir().get_parent_item(ty.hir_id).def_id; - let ty = ItemCtxt::new(tcx, item_def_id).lower_ty(hir_ty); - - // Iterate through the generics of the projection to find the one that corresponds to - // the def_id that this query was called with. We filter to only type and const args here - // as a precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't - // but it can't hurt to be safe ^^ - if let ty::Alias(ty::Projection | ty::Inherent, projection) = ty.kind() { - let generics = tcx.generics_of(projection.def_id); - - let arg_index = segment - .args - .and_then(|args| { - args.args - .iter() - .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.hir_id() == arg_hir_id) - }) - .unwrap_or_else(|| { - bug!("no arg matching AnonConst in segment"); - }); - - (generics, arg_index) - } else { - // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU - return Ty::new_error_with_message( - tcx, - span, - "unexpected non-GAT usage of an anon const", - ); - } - } - Node::Expr(&Expr { - kind: - ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)), - .. - }) => { - let body_owner = tcx.hir().enclosing_body_owner(arg_hir_id); - let tables = tcx.typeck(body_owner); - // This may fail in case the method/path does not actually exist. - // As there is no relevant param for `def_id`, we simply return - // `None` here. - let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else { - return Ty::new_error_with_message( - tcx, - span, - format!("unable to find type-dependent def for {parent_node_id:?}"), - ); - }; - let idx = segment - .args - .and_then(|args| { - args.args - .iter() - .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.hir_id() == arg_hir_id) - }) - .unwrap_or_else(|| { - bug!("no arg matching ConstArg in segment"); - }); - - (tcx.generics_of(type_dependent_def), idx) - } - - Node::Ty(&hir::Ty { kind: TyKind::Path(_), .. }) - | Node::Expr(&Expr { kind: ExprKind::Path(_) | ExprKind::Struct(..), .. }) - | Node::TraitRef(..) - | Node::Pat(_) => { - let path = match parent_node { - Node::Ty(&hir::Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. }) - | Node::TraitRef(&TraitRef { path, .. }) => &*path, - Node::Expr(&Expr { - kind: - ExprKind::Path(QPath::Resolved(_, path)) - | ExprKind::Struct(&QPath::Resolved(_, path), ..), - .. - }) => { - let body_owner = tcx.hir().enclosing_body_owner(arg_hir_id); - let _tables = tcx.typeck(body_owner); - &*path - } - Node::Pat(pat) => { - if let Some(path) = get_path_containing_arg_in_pat(pat, arg_hir_id) { - path - } else { - return Ty::new_error_with_message( - tcx, - span, - format!("unable to find const parent for {arg_hir_id} in pat {pat:?}"), - ); - } - } - _ => { - return Ty::new_error_with_message( - tcx, - span, - format!("unexpected const parent path {parent_node:?}"), - ); - } - }; - - // We've encountered an `AnonConst` in some path, so we need to - // figure out which generic parameter it corresponds to and return - // the relevant type. - let Some((arg_index, segment)) = path.segments.iter().find_map(|seg| { - let args = seg.args?; - args.args - .iter() - .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.hir_id() == arg_hir_id) - .map(|index| (index, seg)) - .or_else(|| { - args.constraints - .iter() - .copied() - .filter_map(AssocItemConstraint::ct) - .position(|ct| ct.hir_id == arg_hir_id) - .map(|idx| (idx, seg)) - }) - }) else { - return Ty::new_error_with_message(tcx, span, "no arg matching AnonConst in path"); - }; - - let generics = match tcx.res_generics_def_id(segment.res) { - Some(def_id) => tcx.generics_of(def_id), - None => { - return Ty::new_error_with_message( - tcx, - span, - format!("unexpected anon const res {:?} in path: {:?}", segment.res, path), - ); - } - }; - - (generics, arg_index) - } - _ => { - return Ty::new_error_with_message( - tcx, - span, - format!("unexpected const arg parent in type_of(): {parent_node:?}"), - ); - } - }; - - debug!(?parent_node); - debug!(?generics, ?arg_idx); - if let Some(param_def_id) = generics - .own_params - .iter() - .filter(|param| param.kind.is_ty_or_const()) - .nth(match generics.has_self && generics.parent.is_none() { - true => arg_idx + 1, - false => arg_idx, - }) - .and_then(|param| match param.kind { - ty::GenericParamDefKind::Const { .. } => { - debug!(?param); - Some(param.def_id) - } - _ => None, - }) - { - tcx.type_of(param_def_id).no_bound_vars().expect("const parameter types cannot be generic") - } else { - return Ty::new_error_with_message( + // This is not a `bug!` as const arguments in path segments that did not resolve to anything + // will result in `type_of` never being fed. + _ => Ty::new_error_with_message( tcx, span, - format!("const generic parameter not found in {generics:?} at position {arg_idx:?}"), - ); + "`type_of` called on const argument's anon const before the const argument was lowered", + ), } } -fn get_path_containing_arg_in_pat<'hir>( - pat: &'hir hir::Pat<'hir>, - arg_id: HirId, -) -> Option<&'hir hir::Path<'hir>> { - use hir::*; - - let is_arg_in_path = |p: &hir::Path<'_>| { - p.segments - .iter() - .filter_map(|seg| seg.args) - .flat_map(|args| args.args) - .any(|arg| arg.hir_id() == arg_id) - }; - let mut arg_path = None; - pat.walk(|pat| match pat.kind { - PatKind::Struct(QPath::Resolved(_, path), _, _) - | PatKind::TupleStruct(QPath::Resolved(_, path), _, _) - | PatKind::Path(QPath::Resolved(_, path)) - if is_arg_in_path(path) => - { - arg_path = Some(path); - false - } - _ => true, - }); - arg_path -} - pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, Ty<'_>> { use rustc_hir::*; use rustc_middle::ty::Ty; diff --git a/tests/ui/coroutine/coroutine-in-orphaned-anon-const.rs b/tests/ui/coroutine/coroutine-in-orphaned-anon-const.rs index 07c13239a2ce2..c98ec1de17e39 100644 --- a/tests/ui/coroutine/coroutine-in-orphaned-anon-const.rs +++ b/tests/ui/coroutine/coroutine-in-orphaned-anon-const.rs @@ -3,8 +3,6 @@ trait X { fn test() -> Self::Assoc<{ async {} }>; //~^ ERROR associated type `Assoc` not found for `Self` - //~| ERROR associated type `Assoc` not found for `Self` - } pub fn main() {} diff --git a/tests/ui/coroutine/coroutine-in-orphaned-anon-const.stderr b/tests/ui/coroutine/coroutine-in-orphaned-anon-const.stderr index 864c6556d7990..5855372875320 100644 --- a/tests/ui/coroutine/coroutine-in-orphaned-anon-const.stderr +++ b/tests/ui/coroutine/coroutine-in-orphaned-anon-const.stderr @@ -4,14 +4,6 @@ error[E0220]: associated type `Assoc` not found for `Self` LL | fn test() -> Self::Assoc<{ async {} }>; | ^^^^^ associated type `Assoc` not found -error[E0220]: associated type `Assoc` not found for `Self` - --> $DIR/coroutine-in-orphaned-anon-const.rs:4:24 - | -LL | fn test() -> Self::Assoc<{ async {} }>; - | ^^^^^ associated type `Assoc` not found - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/traits/bound/unknown-assoc-with-const-arg.rs b/tests/ui/traits/bound/unknown-assoc-with-const-arg.rs index 48a98efea5ef9..0da68afb59261 100644 --- a/tests/ui/traits/bound/unknown-assoc-with-const-arg.rs +++ b/tests/ui/traits/bound/unknown-assoc-with-const-arg.rs @@ -3,7 +3,6 @@ trait X { fn a() -> T::unknown<{}> {} //~^ ERROR: associated type `unknown` not found for `T` - //~| ERROR: associated type `unknown` not found for `T` } trait Y { @@ -14,7 +13,6 @@ trait Y { trait Z { fn a() -> T::unknown<{}> {} //~^ ERROR: associated type `unknown` not found for `T` - //~| ERROR: associated type `unknown` not found for `T` } fn main() {} diff --git a/tests/ui/traits/bound/unknown-assoc-with-const-arg.stderr b/tests/ui/traits/bound/unknown-assoc-with-const-arg.stderr index 9598c373e6e8a..49e41f75ff35a 100644 --- a/tests/ui/traits/bound/unknown-assoc-with-const-arg.stderr +++ b/tests/ui/traits/bound/unknown-assoc-with-const-arg.stderr @@ -5,34 +5,18 @@ LL | fn a() -> T::unknown<{}> {} | ^^^^^^^ associated type `unknown` not found error[E0220]: associated type `unknown` not found for `T` - --> $DIR/unknown-assoc-with-const-arg.rs:15:18 + --> $DIR/unknown-assoc-with-const-arg.rs:14:18 | LL | fn a() -> T::unknown<{}> {} | ^^^^^^^ associated type `unknown` not found -error[E0220]: associated type `unknown` not found for `T` - --> $DIR/unknown-assoc-with-const-arg.rs:4:21 - | -LL | fn a() -> T::unknown<{}> {} - | ^^^^^^^ associated type `unknown` not found - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0220]: associated type `unknown` not found for `T` - --> $DIR/unknown-assoc-with-const-arg.rs:15:18 - | -LL | fn a() -> T::unknown<{}> {} - | ^^^^^^^ associated type `unknown` not found - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error[E0433]: failed to resolve: use of undeclared type `NOT_EXIST` - --> $DIR/unknown-assoc-with-const-arg.rs:10:15 + --> $DIR/unknown-assoc-with-const-arg.rs:9:15 | LL | fn a() -> NOT_EXIST::unknown<{}> {} | ^^^^^^^^^ use of undeclared type `NOT_EXIST` -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0220, E0433. For more information about an error, try `rustc --explain E0220`. From 52d1c30d3ee692c47691c8c96dd62368af2de9c5 Mon Sep 17 00:00:00 2001 From: Boxy Date: Wed, 4 Dec 2024 00:19:26 +0000 Subject: [PATCH 2/2] Add comment to test --- tests/ui/const-generics/issues/cg-in-dyn-issue-128176.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ui/const-generics/issues/cg-in-dyn-issue-128176.rs b/tests/ui/const-generics/issues/cg-in-dyn-issue-128176.rs index d163238c6d536..5a67d34d6e5a1 100644 --- a/tests/ui/const-generics/issues/cg-in-dyn-issue-128176.rs +++ b/tests/ui/const-generics/issues/cg-in-dyn-issue-128176.rs @@ -1,6 +1,7 @@ //@ check-pass -// Regression test for #128176. +// Regression test for #128176. Previously we would call `type_of` on the `1` anon const +// before the anon const had been lowered and had the `type_of` fed with a result. #![feature(generic_const_exprs)] #![feature(dyn_compatible_for_dispatch)]