Rollup merge of #92875 - BoxyUwU:infer_arg_opt_const_param_of, r=lcnr
Make `opt_const_param_of` work in the presence of `GenericArg::Infer` highly recommend viewing the first and second commits on their own rather than looking at file changes 🤣 Because we filtered args down to just const args we would ignore `GenericArg::Infer` which made us get a `arg_index` which was wrong by however many const `GenericArg::Infer` came previously [example](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=46dba6a53aca6333028a10908ef16e0b) of the [bugs](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=a8eebced26eefa4119fc2e7ae0c76de6) fixed. r? ```@lcnr```
This commit is contained in:
commit
6c94f99d83
6 changed files with 228 additions and 216 deletions
|
@ -293,10 +293,6 @@ impl GenericArg<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_const(&self) -> bool {
|
|
||||||
matches!(self, GenericArg::Const(_))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_synthetic(&self) -> bool {
|
pub fn is_synthetic(&self) -> bool {
|
||||||
matches!(self, GenericArg::Lifetime(lifetime) if lifetime.name.ident() == Ident::empty())
|
matches!(self, GenericArg::Lifetime(lifetime) if lifetime.name.ident() == Ident::empty())
|
||||||
}
|
}
|
||||||
|
@ -318,6 +314,13 @@ impl GenericArg<'_> {
|
||||||
GenericArg::Infer(_) => ast::ParamKindOrd::Infer,
|
GenericArg::Infer(_) => ast::ParamKindOrd::Infer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_ty_or_const(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
GenericArg::Lifetime(_) => false,
|
||||||
|
GenericArg::Type(_) | GenericArg::Const(_) | GenericArg::Infer(_) => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, HashStable_Generic)]
|
#[derive(Debug, HashStable_Generic)]
|
||||||
|
|
|
@ -31,6 +31,13 @@ impl GenericParamDefKind {
|
||||||
GenericParamDefKind::Const { .. } => ast::ParamKindOrd::Const,
|
GenericParamDefKind::Const { .. } => ast::ParamKindOrd::Const,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_ty_or_const(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
GenericParamDefKind::Lifetime => false,
|
||||||
|
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||||
|
|
|
@ -18,6 +18,7 @@ use super::{bad_placeholder, is_suggestable_infer_ty};
|
||||||
/// Computes the relevant generic parameter for a potential generic const argument.
|
/// Computes the relevant generic parameter for a potential generic const argument.
|
||||||
///
|
///
|
||||||
/// This should be called using the query `tcx.opt_const_param_of`.
|
/// This should be called using the query `tcx.opt_const_param_of`.
|
||||||
|
#[instrument(level = "debug", skip(tcx))]
|
||||||
pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> {
|
pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> {
|
||||||
// FIXME(generic_arg_infer): allow for returning DefIds of inference of
|
// FIXME(generic_arg_infer): allow for returning DefIds of inference of
|
||||||
// GenericArg::Infer below. This may require a change where GenericArg::Infer has some flag
|
// GenericArg::Infer below. This may require a change where GenericArg::Infer has some flag
|
||||||
|
@ -25,71 +26,69 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
|
||||||
use hir::*;
|
use hir::*;
|
||||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||||
|
|
||||||
if let Node::AnonConst(_) = tcx.hir().get(hir_id) {
|
match tcx.hir().get(hir_id) {
|
||||||
let parent_node_id = tcx.hir().get_parent_node(hir_id);
|
Node::AnonConst(_) => (),
|
||||||
let parent_node = tcx.hir().get(parent_node_id);
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
match parent_node {
|
let parent_node_id = tcx.hir().get_parent_node(hir_id);
|
||||||
// This match arm is for when the def_id appears in a GAT whose
|
let parent_node = tcx.hir().get(parent_node_id);
|
||||||
// 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 typchecking 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 @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => {
|
|
||||||
// Find the Item containing the associated type so we can create an ItemCtxt.
|
|
||||||
// Using the ItemCtxt convert the HIR for the unresolved assoc type into a
|
|
||||||
// ty which is a fully resolved projection.
|
|
||||||
// For the code example above, this would mean converting Self::Assoc<3>
|
|
||||||
// into a ty::Projection(<Self as Foo>::Assoc<3>)
|
|
||||||
let item_hir_id = tcx
|
|
||||||
.hir()
|
|
||||||
.parent_iter(hir_id)
|
|
||||||
.filter(|(_, node)| matches!(node, Node::Item(_)))
|
|
||||||
.map(|(id, _)| id)
|
|
||||||
.next()
|
|
||||||
.unwrap();
|
|
||||||
let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id();
|
|
||||||
let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>;
|
|
||||||
let ty = item_ctxt.ast_ty_to_ty(hir_ty);
|
|
||||||
|
|
||||||
// Iterate through the generics of the projection to find the one that corresponds to
|
let (generics, arg_idx) = match parent_node {
|
||||||
// the def_id that this query was called with. We filter to only const args here as a
|
// This match arm is for when the def_id appears in a GAT whose
|
||||||
// precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
|
// path can't be resolved without typechecking e.g.
|
||||||
// but it can't hurt to be safe ^^
|
//
|
||||||
if let ty::Projection(projection) = ty.kind() {
|
// trait Foo {
|
||||||
let generics = tcx.generics_of(projection.item_def_id);
|
// 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 typchecking 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 @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => {
|
||||||
|
// Find the Item containing the associated type so we can create an ItemCtxt.
|
||||||
|
// Using the ItemCtxt convert the HIR for the unresolved assoc type into a
|
||||||
|
// ty which is a fully resolved projection.
|
||||||
|
// For the code example above, this would mean converting Self::Assoc<3>
|
||||||
|
// into a ty::Projection(<Self as Foo>::Assoc<3>)
|
||||||
|
let item_hir_id = tcx
|
||||||
|
.hir()
|
||||||
|
.parent_iter(hir_id)
|
||||||
|
.filter(|(_, node)| matches!(node, Node::Item(_)))
|
||||||
|
.map(|(id, _)| id)
|
||||||
|
.next()
|
||||||
|
.unwrap();
|
||||||
|
let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id();
|
||||||
|
let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>;
|
||||||
|
let ty = item_ctxt.ast_ty_to_ty(hir_ty);
|
||||||
|
|
||||||
let arg_index = segment
|
// Iterate through the generics of the projection to find the one that corresponds to
|
||||||
.args
|
// the def_id that this query was called with. We filter to only const args here as a
|
||||||
.and_then(|args| {
|
// precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
|
||||||
args.args
|
// but it can't hurt to be safe ^^
|
||||||
.iter()
|
if let ty::Projection(projection) = ty.kind() {
|
||||||
.filter(|arg| arg.is_const())
|
let generics = tcx.generics_of(projection.item_def_id);
|
||||||
.position(|arg| arg.id() == hir_id)
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
bug!("no arg matching AnonConst in segment");
|
|
||||||
});
|
|
||||||
|
|
||||||
return generics
|
let arg_index = segment
|
||||||
.params
|
.args
|
||||||
.iter()
|
.and_then(|args| {
|
||||||
.filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const { .. }))
|
args.args
|
||||||
.nth(arg_index)
|
.iter()
|
||||||
.map(|param| param.def_id);
|
.filter(|arg| arg.is_ty_or_const())
|
||||||
}
|
.position(|arg| arg.id() == 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
|
// I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
|
||||||
tcx.sess.delay_span_bug(
|
tcx.sess.delay_span_bug(
|
||||||
tcx.def_span(def_id),
|
tcx.def_span(def_id),
|
||||||
|
@ -97,159 +96,158 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Node::Expr(&Expr {
|
}
|
||||||
kind:
|
Node::Expr(&Expr {
|
||||||
ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
|
kind:
|
||||||
..
|
ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
|
||||||
}) => {
|
..
|
||||||
let body_owner = tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
|
}) => {
|
||||||
let tables = tcx.typeck(body_owner);
|
let body_owner = tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
|
||||||
// This may fail in case the method/path does not actually exist.
|
let tables = tcx.typeck(body_owner);
|
||||||
// As there is no relevant param for `def_id`, we simply return
|
// This may fail in case the method/path does not actually exist.
|
||||||
// `None` here.
|
// As there is no relevant param for `def_id`, we simply return
|
||||||
let type_dependent_def = tables.type_dependent_def_id(parent_node_id)?;
|
// `None` here.
|
||||||
let idx = segment
|
let type_dependent_def = tables.type_dependent_def_id(parent_node_id)?;
|
||||||
.args
|
let idx = segment
|
||||||
.and_then(|args| {
|
.args
|
||||||
args.args
|
.and_then(|args| {
|
||||||
.iter()
|
args.args
|
||||||
.filter(|arg| arg.is_const())
|
.iter()
|
||||||
.position(|arg| arg.id() == hir_id)
|
.filter(|arg| arg.is_ty_or_const())
|
||||||
})
|
.position(|arg| arg.id() == hir_id)
|
||||||
.unwrap_or_else(|| {
|
})
|
||||||
bug!("no arg matching AnonConst in segment");
|
.unwrap_or_else(|| {
|
||||||
});
|
bug!("no arg matching AnonConst in segment");
|
||||||
|
});
|
||||||
|
|
||||||
tcx.generics_of(type_dependent_def)
|
(tcx.generics_of(type_dependent_def), idx)
|
||||||
.params
|
}
|
||||||
.iter()
|
|
||||||
.filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const { .. }))
|
|
||||||
.nth(idx)
|
|
||||||
.map(|param| param.def_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
Node::Ty(&Ty { kind: TyKind::Path(_), .. })
|
Node::Ty(&Ty { kind: TyKind::Path(_), .. })
|
||||||
| Node::Expr(&Expr { kind: ExprKind::Path(_) | ExprKind::Struct(..), .. })
|
| Node::Expr(&Expr { kind: ExprKind::Path(_) | ExprKind::Struct(..), .. })
|
||||||
| Node::TraitRef(..)
|
| Node::TraitRef(..)
|
||||||
| Node::Pat(_) => {
|
| Node::Pat(_) => {
|
||||||
let path = match parent_node {
|
let path = match parent_node {
|
||||||
Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
|
Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
|
||||||
| Node::TraitRef(&TraitRef { path, .. }) => &*path,
|
| Node::TraitRef(&TraitRef { path, .. }) => &*path,
|
||||||
Node::Expr(&Expr {
|
Node::Expr(&Expr {
|
||||||
kind:
|
kind:
|
||||||
ExprKind::Path(QPath::Resolved(_, path))
|
ExprKind::Path(QPath::Resolved(_, path))
|
||||||
| ExprKind::Struct(&QPath::Resolved(_, path), ..),
|
| ExprKind::Struct(&QPath::Resolved(_, path), ..),
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
let body_owner =
|
let body_owner = tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
|
||||||
tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
|
let _tables = tcx.typeck(body_owner);
|
||||||
let _tables = tcx.typeck(body_owner);
|
&*path
|
||||||
&*path
|
}
|
||||||
}
|
Node::Pat(pat) => {
|
||||||
Node::Pat(pat) => {
|
if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
|
||||||
if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
|
path
|
||||||
path
|
} else {
|
||||||
} else {
|
|
||||||
tcx.sess.delay_span_bug(
|
|
||||||
tcx.def_span(def_id),
|
|
||||||
&format!(
|
|
||||||
"unable to find const parent for {} in pat {:?}",
|
|
||||||
hir_id, pat
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
tcx.sess.delay_span_bug(
|
tcx.sess.delay_span_bug(
|
||||||
tcx.def_span(def_id),
|
tcx.def_span(def_id),
|
||||||
&format!("unexpected const parent path {:?}", parent_node),
|
&format!("unable to find const parent for {} in pat {:?}", hir_id, pat),
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
_ => {
|
||||||
|
tcx.sess.delay_span_bug(
|
||||||
|
tcx.def_span(def_id),
|
||||||
|
&format!("unexpected const parent path {:?}", parent_node),
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// We've encountered an `AnonConst` in some path, so we need to
|
// We've encountered an `AnonConst` in some path, so we need to
|
||||||
// figure out which generic parameter it corresponds to and return
|
// figure out which generic parameter it corresponds to and return
|
||||||
// the relevant type.
|
// the relevant type.
|
||||||
let filtered = path
|
let filtered = path
|
||||||
.segments
|
.segments
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|seg| seg.args.map(|args| (args.args, seg)))
|
.filter_map(|seg| seg.args.map(|args| (args.args, seg)))
|
||||||
.find_map(|(args, seg)| {
|
.find_map(|(args, seg)| {
|
||||||
args.iter()
|
args.iter()
|
||||||
.filter(|arg| arg.is_const())
|
.filter(|arg| arg.is_ty_or_const())
|
||||||
.position(|arg| arg.id() == hir_id)
|
.position(|arg| arg.id() == hir_id)
|
||||||
.map(|index| (index, seg))
|
.map(|index| (index, seg))
|
||||||
});
|
});
|
||||||
let (arg_index, segment) = match filtered {
|
let (arg_index, segment) = match filtered {
|
||||||
None => {
|
None => {
|
||||||
tcx.sess.delay_span_bug(
|
tcx.sess
|
||||||
tcx.def_span(def_id),
|
.delay_span_bug(tcx.def_span(def_id), "no arg matching AnonConst in path");
|
||||||
"no arg matching AnonConst in path",
|
return None;
|
||||||
);
|
}
|
||||||
return None;
|
Some(inner) => inner,
|
||||||
}
|
};
|
||||||
Some(inner) => inner,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Try to use the segment resolution if it is valid, otherwise we
|
// Try to use the segment resolution if it is valid, otherwise we
|
||||||
// default to the path resolution.
|
// default to the path resolution.
|
||||||
let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res);
|
let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res);
|
||||||
use def::CtorOf;
|
use def::CtorOf;
|
||||||
let generics = match res {
|
let generics = match res {
|
||||||
Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => tcx.generics_of(
|
Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => tcx
|
||||||
tcx.parent(def_id).and_then(|def_id| tcx.parent(def_id)).unwrap(),
|
.generics_of(tcx.parent(def_id).and_then(|def_id| tcx.parent(def_id)).unwrap()),
|
||||||
),
|
Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Struct, _), def_id) => {
|
||||||
Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Struct, _), def_id) => {
|
tcx.generics_of(tcx.parent(def_id).unwrap())
|
||||||
tcx.generics_of(tcx.parent(def_id).unwrap())
|
}
|
||||||
}
|
// Other `DefKind`s don't have generics and would ICE when calling
|
||||||
// Other `DefKind`s don't have generics and would ICE when calling
|
// `generics_of`.
|
||||||
// `generics_of`.
|
Res::Def(
|
||||||
Res::Def(
|
DefKind::Struct
|
||||||
DefKind::Struct
|
| DefKind::Union
|
||||||
| DefKind::Union
|
| DefKind::Enum
|
||||||
| DefKind::Enum
|
| DefKind::Trait
|
||||||
| DefKind::Trait
|
| DefKind::OpaqueTy
|
||||||
| DefKind::OpaqueTy
|
| DefKind::TyAlias
|
||||||
| DefKind::TyAlias
|
| DefKind::ForeignTy
|
||||||
| DefKind::ForeignTy
|
| DefKind::TraitAlias
|
||||||
| DefKind::TraitAlias
|
| DefKind::AssocTy
|
||||||
| DefKind::AssocTy
|
| DefKind::Fn
|
||||||
| DefKind::Fn
|
| DefKind::AssocFn
|
||||||
| DefKind::AssocFn
|
| DefKind::AssocConst
|
||||||
| DefKind::AssocConst
|
| DefKind::Impl,
|
||||||
| DefKind::Impl,
|
def_id,
|
||||||
def_id,
|
) => tcx.generics_of(def_id),
|
||||||
) => tcx.generics_of(def_id),
|
Res::Err => {
|
||||||
Res::Err => {
|
tcx.sess.delay_span_bug(tcx.def_span(def_id), "anon const with Res::Err");
|
||||||
tcx.sess.delay_span_bug(tcx.def_span(def_id), "anon const with Res::Err");
|
return None;
|
||||||
return None;
|
}
|
||||||
}
|
_ => {
|
||||||
_ => {
|
// If the user tries to specify generics on a type that does not take them,
|
||||||
// If the user tries to specify generics on a type that does not take them,
|
// e.g. `usize<T>`, we may hit this branch, in which case we treat it as if
|
||||||
// e.g. `usize<T>`, we may hit this branch, in which case we treat it as if
|
// no arguments have been passed. An error should already have been emitted.
|
||||||
// no arguments have been passed. An error should already have been emitted.
|
tcx.sess.delay_span_bug(
|
||||||
tcx.sess.delay_span_bug(
|
tcx.def_span(def_id),
|
||||||
tcx.def_span(def_id),
|
&format!("unexpected anon const res {:?} in path: {:?}", res, path),
|
||||||
&format!("unexpected anon const res {:?} in path: {:?}", res, path),
|
);
|
||||||
);
|
return None;
|
||||||
return None;
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
generics
|
(generics, arg_index)
|
||||||
.params
|
}
|
||||||
.iter()
|
_ => return None,
|
||||||
.filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const { .. }))
|
};
|
||||||
.nth(arg_index)
|
|
||||||
.map(|param| param.def_id)
|
debug!(?parent_node);
|
||||||
|
debug!(?generics, ?arg_idx);
|
||||||
|
generics
|
||||||
|
.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,
|
_ => None,
|
||||||
}
|
})
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_path_containing_arg_in_pat<'hir>(
|
fn get_path_containing_arg_in_pat<'hir>(
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
// check-pass
|
||||||
|
#![feature(generic_arg_infer)]
|
||||||
|
|
||||||
|
struct Foo<const N: bool, const M: u8>;
|
||||||
|
struct Bar<const N: u8, const M: u32>;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _: Foo<true, _> = Foo::<_, 1>;
|
||||||
|
let _: Foo<_, 1> = Foo::<true, _>;
|
||||||
|
let _: Bar<1, _> = Bar::<_, 300>;
|
||||||
|
let _: Bar<_, 300> = Bar::<1, _>;
|
||||||
|
}
|
|
@ -4,13 +4,6 @@ error[E0770]: the type of const parameters must not depend on other generic para
|
||||||
LL | fn foo<const N: usize, const A: [u8; N]>() {}
|
LL | fn foo<const N: usize, const A: [u8; N]>() {}
|
||||||
| ^ the type must not depend on the parameter `N`
|
| ^ the type must not depend on the parameter `N`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error: aborting due to previous error
|
||||||
--> $DIR/issue-62878.rs:10:15
|
|
||||||
|
|
|
||||||
LL | foo::<_, {[1]}>();
|
|
||||||
| ^^^ expected `usize`, found array `[{integer}; 1]`
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
For more information about this error, try `rustc --explain E0770`.
|
||||||
|
|
||||||
Some errors have detailed explanations: E0308, E0770.
|
|
||||||
For more information about an error, try `rustc --explain E0308`.
|
|
||||||
|
|
|
@ -7,6 +7,5 @@ fn foo<const N: usize, const A: [u8; N]>() {}
|
||||||
//[min]~| ERROR `[u8; _]` is forbidden as the type of a const generic parameter
|
//[min]~| ERROR `[u8; _]` is forbidden as the type of a const generic parameter
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
foo::<_, {[1]}>();
|
foo::<_, { [1] }>();
|
||||||
//[full]~^ ERROR mismatched types
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue