Don't try and handle unfed type_of
on anon consts
This commit is contained in:
parent
c44b3d50fe
commit
ec036cda3f
6 changed files with 14 additions and 270 deletions
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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<const N: usize>;
|
||||
// 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 <Self as Foo>::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, `<Self as Foo>::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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue