Auto merge of #125915 - camelid:const-arg-refactor, r=BoxyUwU

Represent type-level consts with new-and-improved `hir::ConstArg`

### Summary

This is a step toward `min_generic_const_exprs`. We now represent all const
generic arguments using an enum that differentiates between const *paths*
(temporarily just bare const params) and arbitrary anon consts that may perform
computations. This will enable us to cleanly implement the `min_generic_const_args`
plan of allowing the use of generics in paths used as const args, while
disallowing their use in arbitrary anon consts. Here is a summary of the salient
aspects of this change:

- Add `current_def_id_parent` to `LoweringContext`

  This is needed to track anon const parents properly once we implement
  `ConstArgKind::Path` (which requires moving anon const def-creation
  outside of `DefCollector`).

- Create `hir::ConstArgKind` enum with `Path` and `Anon` variants. Use it in the
  existing `hir::ConstArg` struct, replacing the previous `hir::AnonConst` field.

- Use `ConstArg` for all instances of const args. Specifically, use it instead
  of `AnonConst` for assoc item constraints, array lengths, and const param
  defaults.

- Some `ast::AnonConst`s now have their `DefId`s created in
  rustc_ast_lowering rather than `DefCollector`. This is because in some
  cases they will end up becoming a `ConstArgKind::Path` instead, which
  has no `DefId`. We have to solve this in a hacky way where we guess
  whether the `AnonConst` could end up as a path const since we can't
  know for sure until after name resolution (`N` could refer to a free
  const or a nullary struct). If it has no chance as being a const
  param, then we create a `DefId` in `DefCollector` -- otherwise we
  decide during ast_lowering. This will have to be updated once all path
  consts use `ConstArgKind::Path`.

- We explicitly use `ConstArgHasType` for array lengths, rather than
  implicitly relying on anon const type feeding -- this is due to the
  addition of `ConstArgKind::Path`.

- Some tests have their outputs changed, but the changes are for the
  most part minor (including removing duplicate or almost-duplicate
  errors). One test now ICEs, but it is for an incomplete, unstable
  feature and is now tracked at https://github.com/rust-lang/rust/issues/127009.

### Followup items post-merge

- Use `ConstArgKind::Path` for all const paths, not just const params.
- Fix (no github dont close this issue) #127009
- If a path in generic args doesn't resolve as a type, try to resolve as a const
  instead (do this in rustc_resolve). Then remove the special-casing from
  `rustc_ast_lowering`, so that all params will automatically be lowered as
  `ConstArgKind::Path`.
- (?) Consider making `const_evaluatable_unchecked` a hard error, or at least
  trying it in crater

r? `@BoxyUwU`
This commit is contained in:
bors 2024-07-19 08:44:51 +00:00
commit 8c3a94a1c7
72 changed files with 853 additions and 543 deletions

View file

@ -187,7 +187,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
.emit();
}
hir::InlineAsmOperand::Const {
anon_const: self.lower_anon_const(anon_const),
anon_const: self.lower_anon_const_to_anon_const(anon_const),
}
}
InlineAsmOperand::Sym { sym } => {
@ -222,18 +222,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
};
// Wrap the expression in an AnonConst.
let parent_def_id = self.current_hir_id_owner;
let parent_def_id = self.current_def_id_parent;
let node_id = self.next_node_id();
self.create_def(
parent_def_id.def_id,
node_id,
kw::Empty,
DefKind::AnonConst,
*op_sp,
);
// HACK(min_generic_const_args): see lower_anon_const
if !expr.is_potential_trivial_const_arg() {
self.create_def(
parent_def_id,
node_id,
kw::Empty,
DefKind::AnonConst,
*op_sp,
);
}
let anon_const = AnonConst { id: node_id, value: P(expr) };
hir::InlineAsmOperand::SymFn {
anon_const: self.lower_anon_const(&anon_const),
anon_const: self.lower_anon_const_to_anon_const(&anon_const),
}
}
}

View file

@ -75,10 +75,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
let kind = match &e.kind {
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
ExprKind::ConstBlock(c) => {
let c = self.with_new_scopes(c.value.span, |this| hir::ConstBlock {
def_id: this.local_def_id(c.id),
hir_id: this.lower_node_id(c.id),
body: this.lower_const_body(c.value.span, Some(&c.value)),
let c = self.with_new_scopes(c.value.span, |this| {
let def_id = this.local_def_id(c.id);
hir::ConstBlock {
def_id,
hir_id: this.lower_node_id(c.id),
body: this.with_def_id_parent(def_id, |this| {
this.lower_const_body(c.value.span, Some(&c.value))
}),
}
});
hir::ExprKind::ConstBlock(c)
}
@ -377,17 +382,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
let mut generic_args = ThinVec::new();
for (idx, arg) in args.into_iter().enumerate() {
if legacy_args_idx.contains(&idx) {
let parent_def_id = self.current_hir_id_owner;
let parent_def_id = self.current_def_id_parent;
let node_id = self.next_node_id();
// Add a definition for the in-band const def.
self.create_def(
parent_def_id.def_id,
node_id,
kw::Empty,
DefKind::AnonConst,
f.span,
);
// HACK(min_generic_const_args): see lower_anon_const
if !arg.is_potential_trivial_const_arg() {
// Add a definition for the in-band const def.
self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span);
}
let anon_const = AnonConst { id: node_id, value: arg };
generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
@ -622,6 +624,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
coroutine_source: hir::CoroutineSource,
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
) -> hir::ExprKind<'hir> {
let closure_def_id = self.local_def_id(closure_node_id);
let coroutine_kind = hir::CoroutineKind::Desugared(desugaring_kind, coroutine_source);
// The `async` desugaring takes a resume argument and maintains a `task_context`,
@ -672,22 +675,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
lifetime_elision_allowed: false,
});
let body = self.lower_body(move |this| {
this.coroutine_kind = Some(coroutine_kind);
let body = self.with_def_id_parent(closure_def_id, move |this| {
this.lower_body(move |this| {
this.coroutine_kind = Some(coroutine_kind);
let old_ctx = this.task_context;
if task_context.is_some() {
this.task_context = task_context;
}
let res = body(this);
this.task_context = old_ctx;
let old_ctx = this.task_context;
if task_context.is_some() {
this.task_context = task_context;
}
let res = body(this);
this.task_context = old_ctx;
(params, res)
(params, res)
})
});
// `static |<_task_context?>| -> <return_ty> { <body> }`:
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
def_id: self.local_def_id(closure_node_id),
def_id: closure_def_id,
binder: hir::ClosureBinder::Default,
capture_clause,
bound_generic_params: &[],
@ -966,27 +971,30 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn_decl_span: Span,
fn_arg_span: Span,
) -> hir::ExprKind<'hir> {
let closure_def_id = self.local_def_id(closure_id);
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
let mut coroutine_kind = if this
.attrs
.get(&closure_hir_id.local_id)
.is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine)))
{
Some(hir::CoroutineKind::Coroutine(Movability::Movable))
} else {
None
};
let body_id = this.lower_fn_body(decl, |this| {
this.coroutine_kind = coroutine_kind;
let e = this.lower_expr_mut(body);
coroutine_kind = this.coroutine_kind;
e
});
let coroutine_option =
this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);
(body_id, coroutine_option)
this.with_def_id_parent(closure_def_id, move |this| {
let mut coroutine_kind = if this
.attrs
.get(&closure_hir_id.local_id)
.is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine)))
{
Some(hir::CoroutineKind::Coroutine(Movability::Movable))
} else {
None
};
let body_id = this.lower_fn_body(decl, |this| {
this.coroutine_kind = coroutine_kind;
let e = this.lower_expr_mut(body);
coroutine_kind = this.coroutine_kind;
e
});
let coroutine_option =
this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);
(body_id, coroutine_option)
})
});
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
@ -994,7 +1002,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let fn_decl = self.lower_fn_decl(decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
let c = self.arena.alloc(hir::Closure {
def_id: self.local_def_id(closure_id),
def_id: closure_def_id,
binder: binder_clause,
capture_clause,
bound_generic_params,
@ -1066,6 +1074,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn_decl_span: Span,
fn_arg_span: Span,
) -> hir::ExprKind<'hir> {
let closure_def_id = self.local_def_id(closure_id);
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
assert_matches!(
@ -1075,27 +1084,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
let body = self.with_new_scopes(fn_decl_span, |this| {
let inner_decl =
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
this.with_def_id_parent(closure_def_id, |this| {
let inner_decl =
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
// Transform `async |x: u8| -> X { ... }` into
// `|x: u8| || -> X { ... }`.
let body_id = this.lower_body(|this| {
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
&inner_decl,
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
fn_decl_span,
body.span,
coroutine_kind,
hir::CoroutineSource::Closure,
);
// Transform `async |x: u8| -> X { ... }` into
// `|x: u8| || -> X { ... }`.
let body_id = this.lower_body(|this| {
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
&inner_decl,
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
fn_decl_span,
body.span,
coroutine_kind,
hir::CoroutineSource::Closure,
);
let hir_id = this.lower_node_id(coroutine_kind.closure_id());
this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id);
let hir_id = this.lower_node_id(coroutine_kind.closure_id());
this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id);
(parameters, expr)
});
body_id
(parameters, expr)
});
body_id
})
});
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
@ -1106,7 +1117,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_fn_decl(&decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
let c = self.arena.alloc(hir::Closure {
def_id: self.local_def_id(closure_id),
def_id: closure_def_id,
binder: binder_clause,
capture_clause,
bound_generic_params,

View file

@ -181,7 +181,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
intravisit::walk_generic_param(self, param);
}
fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) {
fn visit_const_param_default(&mut self, param: HirId, ct: &'hir ConstArg<'hir>) {
self.with_parent(param, |this| {
intravisit::walk_const_param_default(this, ct);
})
@ -229,6 +229,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
}
fn visit_anon_const(&mut self, constant: &'hir AnonConst) {
// FIXME: use real span?
self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant));
self.with_parent(constant.hir_id, |this| {
@ -244,6 +245,15 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
});
}
fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir>) {
// FIXME: use real span?
self.insert(DUMMY_SP, const_arg.hir_id, Node::ConstArg(const_arg));
self.with_parent(const_arg.hir_id, |this| {
intravisit::walk_const_arg(this, const_arg);
});
}
fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
self.insert(expr.span, expr.hir_id, Node::Expr(expr));

View file

@ -61,7 +61,10 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
for (def_id, info) in lctx.children {
let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
debug_assert!(matches!(owner, hir::MaybeOwner::Phantom));
debug_assert!(
matches!(owner, hir::MaybeOwner::Phantom),
"duplicate copy of {def_id:?} in lctx.children"
);
*owner = info;
}
}
@ -713,7 +716,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir_id,
def_id: self.local_def_id(v.id),
data: self.lower_variant_data(hir_id, &v.data),
disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const(e)),
disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const_to_anon_const(e)),
ident: self.lower_ident(v.ident),
span: self.lower_span(v.span),
}
@ -1601,7 +1604,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
if let Some((span, hir_id, def_id)) = host_param_parts {
let const_node_id = self.next_node_id();
let anon_const =
let anon_const_did =
self.create_def(def_id, const_node_id, kw::Empty, DefKind::AnonConst, span);
let const_id = self.next_id();
@ -1609,7 +1612,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let bool_id = self.next_id();
self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
self.children.push((anon_const, hir::MaybeOwner::NonOwner(const_id)));
self.children.push((anon_const_did, hir::MaybeOwner::NonOwner(const_id)));
let const_body = self.lower_body(|this| {
(
@ -1624,6 +1627,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
)
});
let default_ac = self.arena.alloc(hir::AnonConst {
def_id: anon_const_did,
hir_id: const_id,
body: const_body,
span,
});
let default_ct = self.arena.alloc(hir::ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Anon(default_ac),
is_desugared_from_effects: false,
});
let param = hir::GenericParam {
def_id,
hir_id,
@ -1648,12 +1662,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
)),
)),
// FIXME(effects) we might not need a default.
default: Some(self.arena.alloc(hir::AnonConst {
def_id: anon_const,
hir_id: const_id,
body: const_body,
span,
})),
default: Some(default_ct),
is_host_effect: true,
synthetic: true,
},

View file

@ -120,6 +120,18 @@ struct LoweringContext<'a, 'hir> {
is_in_dyn_type: bool,
current_hir_id_owner: hir::OwnerId,
/// Why do we need this in addition to [`Self::current_hir_id_owner`]?
///
/// Currently (as of June 2024), anonymous constants are not HIR owners; however,
/// they do get their own DefIds. Some of these DefIds have to be created during
/// AST lowering, rather than def collection, because we can't tell until after
/// name resolution whether an anonymous constant will end up instead being a
/// [`hir::ConstArgKind::Path`]. However, to compute which generics are
/// available to an anonymous constant nested inside another, we need to make
/// sure that the parent is recorded as the parent anon const, not the enclosing
/// item. So we need to track parent defs differently from HIR owners, since they
/// will be finer-grained in the case of anon consts.
current_def_id_parent: LocalDefId,
item_local_id_counter: hir::ItemLocalId,
trait_map: ItemLocalMap<Box<[TraitCandidate]>>,
@ -162,6 +174,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
attrs: SortedMap::default(),
children: Vec::default(),
current_hir_id_owner: hir::CRATE_OWNER_ID,
current_def_id_parent: CRATE_DEF_ID,
item_local_id_counter: hir::ItemLocalId::ZERO,
node_id_to_local_id: Default::default(),
trait_map: Default::default(),
@ -592,7 +605,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO);
debug_assert_eq!(_old, None);
let item = f(self);
let item = self.with_def_id_parent(def_id, f);
debug_assert_eq!(def_id, item.def_id().def_id);
// `f` should have consumed all the elements in these vectors when constructing `item`.
debug_assert!(self.impl_trait_defs.is_empty());
@ -612,6 +625,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.children.push((def_id, hir::MaybeOwner::Owner(info)));
}
fn with_def_id_parent<T>(&mut self, parent: LocalDefId, f: impl FnOnce(&mut Self) -> T) -> T {
let current_def_id_parent = std::mem::replace(&mut self.current_def_id_parent, parent);
let result = f(self);
self.current_def_id_parent = current_def_id_parent;
result
}
/// Installs the remapping `remap` in scope while `f` is being executed.
/// This causes references to the `LocalDefId` keys to be changed to
/// refer to the values instead.
@ -806,7 +826,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
LifetimeRes::Fresh { param, kind, .. } => {
// Late resolution delegates to us the creation of the `LocalDefId`.
let _def_id = self.create_def(
self.current_hir_id_owner.def_id,
self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent?
param,
kw::UnderscoreLifetime,
DefKind::LifetimeParam,
@ -1044,7 +1064,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
AssocItemConstraintKind::Equality { term } => {
let term = match term {
Term::Ty(ty) => self.lower_ty(ty, itctx).into(),
Term::Const(c) => self.lower_anon_const(c).into(),
Term::Const(c) => self.lower_anon_const_to_const_arg(c).into(),
};
hir::AssocItemConstraintKind::Equality { term }
}
@ -1150,42 +1170,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ty,
);
// Construct an AnonConst where the expr is the "ty"'s path.
let parent_def_id = self.current_hir_id_owner;
let node_id = self.next_node_id();
let span = self.lower_span(ty.span);
// Add a definition for the in-band const def.
let def_id = self.create_def(
parent_def_id.def_id,
node_id,
kw::Empty,
DefKind::AnonConst,
span,
);
let path_expr = Expr {
id: ty.id,
kind: ExprKind::Path(None, path.clone()),
span,
attrs: AttrVec::new(),
tokens: None,
};
let ct = self.with_new_scopes(span, |this| {
self.arena.alloc(hir::AnonConst {
def_id,
hir_id: this.lower_node_id(node_id),
body: this
.lower_const_body(path_expr.span, Some(&path_expr)),
span,
})
});
return GenericArg::Const(ConstArg {
value: ct,
is_desugared_from_effects: false,
});
let ct =
self.lower_const_path_to_const_arg(path, res, ty.id, ty.span);
return GenericArg::Const(ct);
}
}
}
@ -1193,10 +1180,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
GenericArg::Type(self.lower_ty(ty, itctx))
}
ast::GenericArg::Const(ct) => GenericArg::Const(ConstArg {
value: self.lower_anon_const(ct),
is_desugared_from_effects: false,
}),
ast::GenericArg::Const(ct) => GenericArg::Const(self.lower_anon_const_to_const_arg(ct)),
}
}
@ -1355,7 +1339,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
TyKind::Array(ty, length) => {
hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length))
}
TyKind::Typeof(expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)),
TyKind::Typeof(expr) => hir::TyKind::Typeof(self.lower_anon_const_to_anon_const(expr)),
TyKind::TraitObject(bounds, kind) => {
let mut lifetime_bound = None;
let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
@ -1429,7 +1413,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
);
self.create_def(
self.current_hir_id_owner.def_id,
self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent?
*def_node_id,
ident.name,
DefKind::TyParam,
@ -1637,7 +1621,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
) -> hir::TyKind<'hir> {
let opaque_ty_def_id = self.create_def(
self.current_hir_id_owner.def_id,
self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent?
opaque_ty_node_id,
kw::Empty,
DefKind::OpaqueTy,
@ -2222,7 +2206,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
false
}
})
.map(|def| self.lower_anon_const(def));
.map(|def| self.lower_anon_const_to_const_arg(def));
(
hir::ParamName::Plain(self.lower_ident(param.ident)),
@ -2360,19 +2344,153 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
"using `_` for array lengths is unstable",
)
.stash(c.value.span, StashKey::UnderscoreForArrayLengths);
hir::ArrayLen::Body(self.lower_anon_const(c))
hir::ArrayLen::Body(self.lower_anon_const_to_const_arg(c))
}
}
_ => hir::ArrayLen::Body(self.lower_anon_const(c)),
_ => hir::ArrayLen::Body(self.lower_anon_const_to_const_arg(c)),
}
}
fn lower_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst {
self.arena.alloc(self.with_new_scopes(c.value.span, |this| hir::AnonConst {
def_id: this.local_def_id(c.id),
hir_id: this.lower_node_id(c.id),
body: this.lower_const_body(c.value.span, Some(&c.value)),
span: this.lower_span(c.value.span),
#[instrument(level = "debug", skip(self))]
fn lower_const_path_to_const_arg(
&mut self,
path: &Path,
res: Res<NodeId>,
ty_id: NodeId,
span: Span,
) -> &'hir hir::ConstArg<'hir> {
let ct_kind = match res {
Res::Def(DefKind::ConstParam, _) => {
let qpath = self.lower_qpath(
ty_id,
&None,
path,
ParamMode::Optional,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
hir::ConstArgKind::Path(qpath)
}
_ => {
// Construct an AnonConst where the expr is the "ty"'s path.
let parent_def_id = self.current_def_id_parent;
let node_id = self.next_node_id();
let span = self.lower_span(span);
// Add a definition for the in-band const def.
let def_id =
self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span);
let hir_id = self.lower_node_id(node_id);
let path_expr = Expr {
id: ty_id,
kind: ExprKind::Path(None, path.clone()),
span,
attrs: AttrVec::new(),
tokens: None,
};
let ct = self.with_new_scopes(span, |this| {
self.arena.alloc(hir::AnonConst {
def_id,
hir_id,
body: this.with_def_id_parent(def_id, |this| {
this.lower_const_body(path_expr.span, Some(&path_expr))
}),
span,
})
});
hir::ConstArgKind::Anon(ct)
}
};
self.arena.alloc(hir::ConstArg {
hir_id: self.next_id(),
kind: ct_kind,
is_desugared_from_effects: false,
})
}
/// See [`hir::ConstArg`] for when to use this function vs
/// [`Self::lower_anon_const_to_anon_const`].
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::ConstArg<'hir> {
self.arena.alloc(self.lower_anon_const_to_const_arg_direct(anon))
}
#[instrument(level = "debug", skip(self))]
fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
let expr = if let ExprKind::Block(block, _) = &anon.value.kind
&& let [stmt] = block.stmts.as_slice()
&& let StmtKind::Expr(expr) = &stmt.kind
&& let ExprKind::Path(..) = &expr.kind
{
expr
} else {
&anon.value
};
let maybe_res =
self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
debug!("res={:?}", maybe_res);
// FIXME(min_generic_const_args): for now we only lower params to ConstArgKind::Path
if let Some(res) = maybe_res
&& let Res::Def(DefKind::ConstParam, _) = res
&& let ExprKind::Path(qself, path) = &expr.kind
{
let qpath = self.lower_qpath(
expr.id,
qself,
path,
ParamMode::Optional,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
return ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Path(qpath),
is_desugared_from_effects: false,
};
}
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Anon(lowered_anon),
is_desugared_from_effects: false,
}
}
/// See [`hir::ConstArg`] for when to use this function vs
/// [`Self::lower_anon_const_to_const_arg`].
fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst {
if c.value.is_potential_trivial_const_arg() {
// HACK(min_generic_const_args): see DefCollector::visit_anon_const
// Over there, we guess if this is a bare param and only create a def if
// we think it's not. However we may can guess wrong (see there for example)
// in which case we have to create the def here.
self.create_def(
self.current_def_id_parent,
c.id,
kw::Empty,
DefKind::AnonConst,
c.value.span,
);
}
self.arena.alloc(self.with_new_scopes(c.value.span, |this| {
let def_id = this.local_def_id(c.id);
let hir_id = this.lower_node_id(c.id);
hir::AnonConst {
def_id,
hir_id,
body: this.with_def_id_parent(def_id, |this| {
this.lower_const_body(c.value.span, Some(&c.value))
}),
span: this.lower_span(c.value.span),
}
}))
}

View file

@ -228,13 +228,53 @@ impl<'hir> PathSegment<'hir> {
}
}
/// A constant that enters the type system, used for arguments to const generics (e.g. array lengths).
///
/// These are distinct from [`AnonConst`] as anon consts in the type system are not allowed
/// to use any generic parameters, therefore we must represent `N` differently. Additionally
/// future designs for supporting generic parameters in const arguments will likely not use
/// an anon const based design.
///
/// So, `ConstArg` (specifically, [`ConstArgKind`]) distinguishes between const args
/// that are [just paths](ConstArgKind::Path) (currently just bare const params)
/// versus const args that are literals or have arbitrary computations (e.g., `{ 1 + 3 }`).
#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub struct ConstArg<'hir> {
pub value: &'hir AnonConst,
#[stable_hasher(ignore)]
pub hir_id: HirId,
pub kind: ConstArgKind<'hir>,
/// Indicates whether this comes from a `~const` desugaring.
pub is_desugared_from_effects: bool,
}
impl<'hir> ConstArg<'hir> {
pub fn anon_const_hir_id(&self) -> Option<HirId> {
match self.kind {
ConstArgKind::Anon(ac) => Some(ac.hir_id),
_ => None,
}
}
pub fn span(&self) -> Span {
match self.kind {
ConstArgKind::Path(path) => path.span(),
ConstArgKind::Anon(anon) => anon.span,
}
}
}
/// See [`ConstArg`].
#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub enum ConstArgKind<'hir> {
/// **Note:** Currently this is only used for bare const params
/// (`N` where `fn foo<const N: usize>(...)`),
/// not paths to any const (`N` where `const N: usize = ...`).
///
/// However, in the future, we'll be using it for all of those.
Path(QPath<'hir>),
Anon(&'hir AnonConst),
}
#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub struct InferArg {
pub hir_id: HirId,
@ -251,7 +291,7 @@ impl InferArg {
pub enum GenericArg<'hir> {
Lifetime(&'hir Lifetime),
Type(&'hir Ty<'hir>),
Const(ConstArg<'hir>),
Const(&'hir ConstArg<'hir>),
Infer(InferArg),
}
@ -260,7 +300,7 @@ impl GenericArg<'_> {
match self {
GenericArg::Lifetime(l) => l.ident.span,
GenericArg::Type(t) => t.span,
GenericArg::Const(c) => c.value.span,
GenericArg::Const(c) => c.span(),
GenericArg::Infer(i) => i.span,
}
}
@ -269,7 +309,7 @@ impl GenericArg<'_> {
match self {
GenericArg::Lifetime(l) => l.hir_id,
GenericArg::Type(t) => t.hir_id,
GenericArg::Const(c) => c.value.hir_id,
GenericArg::Const(c) => c.hir_id,
GenericArg::Infer(i) => i.hir_id,
}
}
@ -524,7 +564,7 @@ pub enum GenericParamKind<'hir> {
Const {
ty: &'hir Ty<'hir>,
/// Optional default value for the const generic param
default: Option<&'hir AnonConst>,
default: Option<&'hir ConstArg<'hir>>,
is_host_effect: bool,
synthetic: bool,
},
@ -1598,13 +1638,13 @@ pub type Lit = Spanned<LitKind>;
#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub enum ArrayLen<'hir> {
Infer(InferArg),
Body(&'hir AnonConst),
Body(&'hir ConstArg<'hir>),
}
impl ArrayLen<'_> {
pub fn hir_id(&self) -> HirId {
match self {
ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(AnonConst { hir_id, .. }) => {
ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(ConstArg { hir_id, .. }) => {
*hir_id
}
}
@ -2434,7 +2474,7 @@ impl<'hir> AssocItemConstraint<'hir> {
}
/// Obtain the const on the RHS of an assoc const equality constraint if applicable.
pub fn ct(self) -> Option<&'hir AnonConst> {
pub fn ct(self) -> Option<&'hir ConstArg<'hir>> {
match self.kind {
AssocItemConstraintKind::Equality { term: Term::Const(ct) } => Some(ct),
_ => None,
@ -2445,7 +2485,7 @@ impl<'hir> AssocItemConstraint<'hir> {
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum Term<'hir> {
Ty(&'hir Ty<'hir>),
Const(&'hir AnonConst),
Const(&'hir ConstArg<'hir>),
}
impl<'hir> From<&'hir Ty<'hir>> for Term<'hir> {
@ -2454,8 +2494,8 @@ impl<'hir> From<&'hir Ty<'hir>> for Term<'hir> {
}
}
impl<'hir> From<&'hir AnonConst> for Term<'hir> {
fn from(c: &'hir AnonConst) -> Self {
impl<'hir> From<&'hir ConstArg<'hir>> for Term<'hir> {
fn from(c: &'hir ConstArg<'hir>) -> Self {
Term::Const(c)
}
}
@ -3689,6 +3729,7 @@ pub enum Node<'hir> {
Field(&'hir FieldDef<'hir>),
AnonConst(&'hir AnonConst),
ConstBlock(&'hir ConstBlock),
ConstArg(&'hir ConstArg<'hir>),
Expr(&'hir Expr<'hir>),
ExprField(&'hir ExprField<'hir>),
Stmt(&'hir Stmt<'hir>),
@ -3750,6 +3791,7 @@ impl<'hir> Node<'hir> {
Node::Param(..)
| Node::AnonConst(..)
| Node::ConstBlock(..)
| Node::ConstArg(..)
| Node::Expr(..)
| Node::Stmt(..)
| Node::Block(..)
@ -3966,7 +4008,7 @@ mod size_asserts {
static_assert_size!(FnDecl<'_>, 40);
static_assert_size!(ForeignItem<'_>, 72);
static_assert_size!(ForeignItemKind<'_>, 40);
static_assert_size!(GenericArg<'_>, 24);
static_assert_size!(GenericArg<'_>, 16);
static_assert_size!(GenericBound<'_>, 48);
static_assert_size!(Generics<'_>, 56);
static_assert_size!(Impl<'_>, 80);

View file

@ -347,6 +347,9 @@ pub trait Visitor<'v>: Sized {
fn visit_inline_const(&mut self, c: &'v ConstBlock) -> Self::Result {
walk_inline_const(self, c)
}
fn visit_const_arg(&mut self, c: &'v ConstArg<'v>) -> Self::Result {
walk_const_arg(self, c)
}
fn visit_expr(&mut self, ex: &'v Expr<'v>) -> Self::Result {
walk_expr(self, ex)
}
@ -364,7 +367,7 @@ pub trait Visitor<'v>: Sized {
fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) -> Self::Result {
walk_generic_param(self, p)
}
fn visit_const_param_default(&mut self, _param: HirId, ct: &'v AnonConst) -> Self::Result {
fn visit_const_param_default(&mut self, _param: HirId, ct: &'v ConstArg<'v>) -> Self::Result {
walk_const_param_default(self, ct)
}
fn visit_generics(&mut self, g: &'v Generics<'v>) -> Self::Result {
@ -708,7 +711,7 @@ pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen<'v>
match len {
// FIXME: Use `visit_infer` here.
ArrayLen::Infer(InferArg { hir_id, span: _ }) => visitor.visit_id(*hir_id),
ArrayLen::Body(c) => visitor.visit_anon_const(c),
ArrayLen::Body(c) => visitor.visit_const_arg(c),
}
}
@ -725,6 +728,17 @@ pub fn walk_inline_const<'v, V: Visitor<'v>>(
visitor.visit_nested_body(constant.body)
}
pub fn walk_const_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
const_arg: &'v ConstArg<'v>,
) -> V::Result {
try_visit!(visitor.visit_id(const_arg.hir_id));
match &const_arg.kind {
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, const_arg.hir_id, qpath.span()),
ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
}
}
pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) -> V::Result {
try_visit!(visitor.visit_id(expression.hir_id));
match expression.kind {
@ -928,9 +942,9 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(
pub fn walk_const_param_default<'v, V: Visitor<'v>>(
visitor: &mut V,
ct: &'v AnonConst,
ct: &'v ConstArg<'v>,
) -> V::Result {
visitor.visit_anon_const(ct)
visitor.visit_const_arg(ct)
}
pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) -> V::Result {
@ -1216,7 +1230,7 @@ pub fn walk_generic_arg<'v, V: Visitor<'v>>(
match generic_arg {
GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt),
GenericArg::Type(ty) => visitor.visit_ty(ty),
GenericArg::Const(ct) => visitor.visit_anon_const(&ct.value),
GenericArg::Const(ct) => visitor.visit_const_arg(ct),
GenericArg::Infer(inf) => visitor.visit_infer(inf),
}
}
@ -1278,7 +1292,7 @@ pub fn walk_assoc_item_constraint<'v, V: Visitor<'v>>(
match constraint.kind {
AssocItemConstraintKind::Equality { ref term } => match term {
Term::Ty(ref ty) => try_visit!(visitor.visit_ty(ty)),
Term::Const(ref c) => try_visit!(visitor.visit_anon_const(c)),
Term::Const(ref c) => try_visit!(visitor.visit_const_arg(c)),
},
AssocItemConstraintKind::Bound { bounds } => {
walk_list!(visitor, visit_param_bound, bounds)

View file

@ -304,7 +304,9 @@ 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().type_of(default.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);
}
}

View file

@ -13,7 +13,7 @@ use rustc_session::lint;
use rustc_span::symbol::{kw, Symbol};
use rustc_span::Span;
#[instrument(level = "debug", skip(tcx))]
#[instrument(level = "debug", skip(tcx), ret)]
pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
use rustc_hir::*;
@ -102,6 +102,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
None
} else if tcx.features().generic_const_exprs {
let parent_node = tcx.parent_hir_node(hir_id);
debug!(?parent_node);
if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node
&& constant.hir_id == hir_id
{
@ -164,13 +165,17 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
}
} else {
let parent_node = tcx.parent_hir_node(hir_id);
let parent_node = match parent_node {
Node::ConstArg(ca) => tcx.parent_hir_node(ca.hir_id),
_ => parent_node,
};
match parent_node {
// HACK(eddyb) this provides the correct generics for repeat
// expressions' count (i.e. `N` in `[x; N]`), and explicit
// `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
// as they shouldn't be able to cause query cycle errors.
Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. })
if constant.hir_id() == hir_id =>
Node::Expr(Expr { kind: ExprKind::Repeat(_, ArrayLen::Body(ct)), .. })
if ct.anon_const_hir_id() == Some(hir_id) =>
{
Some(parent_did)
}

View file

@ -388,7 +388,7 @@ fn const_evaluatable_predicates_of(
}
}
fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::AnonConst) {
fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::ConstArg<'tcx>) {
// Do not look into const param defaults,
// these get checked when they are actually instantiated.
//

View file

@ -954,7 +954,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
GenericParamKind::Const { ty, default, .. } => {
self.visit_ty(ty);
if let Some(default) = default {
self.visit_body(self.tcx.hir().body(default.body));
self.visit_const_arg(default);
}
}
}
@ -1594,7 +1594,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
i += 1;
}
GenericArg::Const(ct) => {
self.visit_anon_const(&ct.value);
self.visit_const_arg(ct);
i += 1;
}
GenericArg::Infer(inf) => {

View file

@ -35,16 +35,32 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
let parent_node_id = tcx.parent_hir_id(hir_id);
let parent_node = tcx.hir_node(parent_node_id);
let (generics, arg_idx) = match parent_node {
// Easy case: arrays repeat expressions.
Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. })
| Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
if constant.hir_id() == hir_id =>
match parent_node {
// Anon consts "inside" the type system.
Node::ConstArg(&ConstArg {
hir_id: arg_hir_id,
kind: ConstArgKind::Anon(&AnonConst { hir_id: anon_hir_id, .. }),
..
}) if anon_hir_id == hir_id => const_arg_anon_type_of(tcx, arg_hir_id, span),
// Anon consts outside the type system.
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
if asm.operands.iter().any(|(op, _op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const }
| hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id,
_ => false,
}) =>
{
return tcx.types.usize;
tcx.typeck(def_id).node_type(hir_id)
}
Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
}
// Sort of affects the type system, but only for the purpose of diagnostics
// so no need for ConstArg.
Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), span, .. }) if e.hir_id == hir_id => {
let ty = tcx.typeck(def_id).node_type(e.hir_id);
let ty = tcx.typeck(def_id).node_type(tcx.local_def_id_to_hir_id(def_id));
let ty = tcx.fold_regions(ty, |r, _| {
if r.is_erased() { ty::Region::new_error_misc(tcx) } else { r }
});
@ -56,24 +72,35 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
tcx.dcx().emit_err(TypeofReservedKeywordUsed { span, ty, opt_sugg });
return ty;
}
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
if asm.operands.iter().any(|(op, _op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const }
| hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id,
_ => false,
}) =>
_ => Ty::new_error_with_message(
tcx,
span,
format!("unexpected anon const parent in type_of(): {parent_node:?}"),
),
}
}
fn const_arg_anon_type_of<'tcx>(tcx: TyCtxt<'tcx>, arg_hir_id: HirId, span: Span) -> Ty<'tcx> {
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.
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.typeck(def_id).node_type(hir_id);
}
Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
return tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx);
return tcx.types.usize;
}
Node::GenericParam(&GenericParam {
def_id: param_def_id,
kind: GenericParamKind::Const { default: Some(ct), .. },
..
}) if ct.hir_id == hir_id => {
}) if ct.hir_id == arg_hir_id => {
return tcx
.type_of(param_def_id)
.no_bound_vars()
@ -104,7 +131,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
// to a ty::Alias(ty::Projection, `<Self as Foo>::Assoc<3>`).
let item_def_id = tcx
.hir()
.parent_owner_iter(hir_id)
.parent_owner_iter(arg_hir_id)
.find(|(_, node)| matches!(node, OwnerNode::Item(_)))
.unwrap()
.0
@ -124,7 +151,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
args.args
.iter()
.filter(|arg| arg.is_ty_or_const())
.position(|arg| arg.hir_id() == hir_id)
.position(|arg| arg.hir_id() == arg_hir_id)
})
.unwrap_or_else(|| {
bug!("no arg matching AnonConst in segment");
@ -145,7 +172,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
..
}) => {
let body_owner = tcx.hir().enclosing_body_owner(hir_id);
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
@ -163,10 +190,10 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
args.args
.iter()
.filter(|arg| arg.is_ty_or_const())
.position(|arg| arg.hir_id() == hir_id)
.position(|arg| arg.hir_id() == arg_hir_id)
})
.unwrap_or_else(|| {
bug!("no arg matching AnonConst in segment");
bug!("no arg matching ConstArg in segment");
});
(tcx.generics_of(type_dependent_def), idx)
@ -185,18 +212,18 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
| ExprKind::Struct(&QPath::Resolved(_, path), ..),
..
}) => {
let body_owner = tcx.hir().enclosing_body_owner(hir_id);
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, hir_id) {
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 {hir_id} in pat {pat:?}"),
format!("unable to find const parent for {arg_hir_id} in pat {pat:?}"),
);
}
}
@ -217,14 +244,14 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
args.args
.iter()
.filter(|arg| arg.is_ty_or_const())
.position(|arg| arg.hir_id() == hir_id)
.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 == hir_id)
.position(|ct| ct.hir_id == arg_hir_id)
.map(|idx| (idx, seg))
})
}) else {
@ -249,7 +276,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
return Ty::new_error_with_message(
tcx,
span,
format!("unexpected const parent in type_of(): {parent_node:?}"),
format!("unexpected const arg parent in type_of(): {parent_node:?}"),
);
}
};

View file

@ -413,12 +413,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
});
// Provide the resolved type of the associated constant to `type_of(AnonConst)`.
if let Some(anon_const) = constraint.ct() {
let ty = alias_term
.map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args));
let ty =
check_assoc_const_binding_type(self, constraint.ident, ty, constraint.hir_id);
tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty));
if let Some(const_arg) = constraint.ct() {
if let hir::ConstArgKind::Anon(anon_const) = const_arg.kind {
let ty = alias_term
.map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args));
let ty = check_assoc_const_binding_type(
self,
constraint.ident,
ty,
constraint.hir_id,
);
tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty));
}
}
alias_term
@ -435,7 +441,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir::AssocItemConstraintKind::Equality { term } => {
let term = match term {
hir::Term::Ty(ty) => self.lower_ty(ty).into(),
hir::Term::Const(ct) => ty::Const::from_anon_const(tcx, ct.def_id).into(),
hir::Term::Const(ct) => {
ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No).into()
}
};
// Find any late-bound regions declared in `ty` that are not

View file

@ -340,7 +340,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
{
let span = match term {
hir::Term::Ty(ty) => ty.span,
hir::Term::Const(ct) => tcx.def_span(ct.def_id),
hir::Term::Const(ct) => ct.span(),
};
(span, Some(ident.span), assoc_item.kind, assoc_kind)
} else {
@ -1294,8 +1294,7 @@ pub fn prohibit_assoc_item_constraint(
hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(c) },
GenericParamDefKind::Const { .. },
) => {
let span = tcx.hir().span(c.hir_id);
suggest_direct_use(&mut err, span);
suggest_direct_use(&mut err, c.span());
}
(hir::AssocItemConstraintKind::Bound { bounds }, _) => {
// Suggest `impl<T: Bound> Trait<T> for Foo` when finding

View file

@ -113,8 +113,12 @@ fn generic_arg_mismatch_err(
}
}
(GenericArg::Const(cnst), GenericParamDefKind::Type { .. }) => {
let body = tcx.hir().body(cnst.value.body);
if let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body.value.kind
// FIXME(min_generic_const_args): once ConstArgKind::Path is used for non-params too,
// this should match against that instead of ::Anon
if let hir::ConstArgKind::Anon(anon) = cnst.kind
&& let body = tcx.hir().body(anon.body)
&& let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) =
body.value.kind
{
if let Res::Def(DefKind::Fn { .. }, id) = path.res {
err.help(format!("`{}` is a function item, not a type", tcx.item_name(id)));

View file

@ -471,11 +471,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
handle_ty_args(has_default, &inf.to_ty())
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
let did = ct.value.def_id;
tcx.feed_anon_const_type(did, tcx.type_of(param.def_id));
ty::Const::from_anon_const(tcx, did).into()
ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::Param(param.def_id))
.into()
}
(&GenericParamDefKind::Const { .. }, hir::GenericArg::Infer(inf)) => {
(&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
self.lowerer.ct_infer(Some(param), inf.span).into()
}
(kind, arg) => span_bug!(
@ -912,7 +911,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let term: ty::Term<'_> = match term {
hir::Term::Ty(ty) => self.lower_ty(ty).into(),
hir::Term::Const(ct) => {
ty::Const::from_anon_const(tcx, ct.def_id).into()
ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No)
.into()
}
};
// FIXME(#97583): This isn't syntactically well-formed!
@ -2140,7 +2140,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let length = match length {
hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span),
hir::ArrayLen::Body(constant) => {
ty::Const::from_anon_const(tcx, constant.def_id)
ty::Const::from_const_arg(tcx, constant, ty::FeedConstTy::No)
}
};

View file

@ -12,8 +12,9 @@ use rustc_ast_pretty::pp::{self, Breaks};
use rustc_ast_pretty::pprust::{Comments, PrintState};
use rustc_hir as hir;
use rustc_hir::{
BindingMode, ByRef, GenericArg, GenericBound, GenericParam, GenericParamKind, HirId,
LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, TraitBoundModifier,
BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind,
HirId, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term,
TraitBoundModifier,
};
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, Ident, Symbol};
@ -87,6 +88,7 @@ impl<'a> State<'a> {
Node::Variant(a) => self.print_variant(a),
Node::AnonConst(a) => self.print_anon_const(a),
Node::ConstBlock(a) => self.print_inline_const(a),
Node::ConstArg(a) => self.print_const_arg(a),
Node::Expr(a) => self.print_expr(a),
Node::ExprField(a) => self.print_expr_field(a),
Node::Stmt(a) => self.print_stmt(a),
@ -983,7 +985,7 @@ impl<'a> State<'a> {
fn print_array_length(&mut self, len: &hir::ArrayLen<'_>) {
match len {
hir::ArrayLen::Infer(..) => self.word("_"),
hir::ArrayLen::Body(ct) => self.print_anon_const(ct),
hir::ArrayLen::Body(ct) => self.print_const_arg(ct),
}
}
@ -991,6 +993,13 @@ impl<'a> State<'a> {
self.ann.nested(self, Nested::Body(constant.body))
}
fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) {
match &const_arg.kind {
ConstArgKind::Path(qpath) => self.print_qpath(qpath, true),
ConstArgKind::Anon(anon) => self.print_anon_const(anon),
}
}
fn print_call_post(&mut self, args: &[hir::Expr<'_>]) {
self.popen();
self.commasep_exprs(Inconsistent, args);
@ -1679,7 +1688,7 @@ impl<'a> State<'a> {
GenericArg::Lifetime(lt) if !elide_lifetimes => s.print_lifetime(lt),
GenericArg::Lifetime(_) => {}
GenericArg::Type(ty) => s.print_type(ty),
GenericArg::Const(ct) => s.print_anon_const(&ct.value),
GenericArg::Const(ct) => s.print_const_arg(ct),
GenericArg::Infer(_inf) => s.word("_"),
}
});
@ -1720,7 +1729,7 @@ impl<'a> State<'a> {
self.word_space("=");
match term {
Term::Ty(ty) => self.print_type(ty),
Term::Const(ref c) => self.print_anon_const(c),
Term::Const(ref c) => self.print_const_arg(c),
}
}
hir::AssocItemConstraintKind::Bound { bounds } => {
@ -2155,7 +2164,7 @@ impl<'a> State<'a> {
if let Some(default) = default {
self.space();
self.word_space("=");
self.print_anon_const(default);
self.print_const_arg(default);
}
}
}

View file

@ -1439,9 +1439,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
};
if let hir::TyKind::Array(_, length) = ty.peel_refs().kind
&& let hir::ArrayLen::Body(&hir::AnonConst { hir_id, .. }) = length
&& let hir::ArrayLen::Body(ct) = length
{
let span = self.tcx.hir().span(hir_id);
let span = ct.span();
self.dcx().try_steal_modify_and_emit_err(
span,
StashKey::UnderscoreForArrayLengths,

View file

@ -457,22 +457,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn lower_array_length(&self, length: &hir::ArrayLen<'tcx>) -> ty::Const<'tcx> {
match length {
hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span),
hir::ArrayLen::Body(anon_const) => {
let span = self.tcx.def_span(anon_const.def_id);
let c = ty::Const::from_anon_const(self.tcx, anon_const.def_id);
hir::ArrayLen::Body(const_arg) => {
let span = const_arg.span();
let c = ty::Const::from_const_arg(self.tcx, const_arg, ty::FeedConstTy::No);
self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None));
self.normalize(span, c)
}
}
}
pub fn lower_const_arg(&self, hir_ct: &hir::AnonConst, param_def_id: DefId) -> ty::Const<'tcx> {
let did = hir_ct.def_id;
self.tcx.feed_anon_const_type(did, self.tcx.type_of(param_def_id));
let ct = ty::Const::from_anon_const(self.tcx, did);
pub fn lower_const_arg(
&self,
const_arg: &'tcx hir::ConstArg<'tcx>,
param_def_id: DefId,
) -> ty::Const<'tcx> {
let ct =
ty::Const::from_const_arg(self.tcx, const_arg, ty::FeedConstTy::Param(param_def_id));
self.register_wf_obligation(
ct.into(),
self.tcx.hir().span(hir_ct.hir_id),
self.tcx.hir().span(const_arg.hir_id),
ObligationCauseCode::WellFormed(None),
);
ct
@ -1298,7 +1301,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.fcx.lower_ty(ty).raw.into()
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
self.fcx.lower_const_arg(&ct.value, param.def_id).into()
self.fcx.lower_const_arg(ct, param.def_id).into()
}
(GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
self.fcx.ty_infer(Some(param), inf.span).into()

View file

@ -400,7 +400,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self.cfcx.lower_ty(ty).raw.into()
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
self.cfcx.lower_const_arg(&ct.value, param.def_id).into()
self.cfcx.lower_const_arg(ct, param.def_id).into()
}
(GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
self.cfcx.ty_infer(Some(param), inf.span).into()

View file

@ -1762,9 +1762,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
};
if let Some(tykind) = tykind
&& let hir::TyKind::Array(_, length) = tykind
&& let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
&& let hir::ArrayLen::Body(ct) = length
{
let span = self.tcx.hir().span(*hir_id);
let span = ct.span();
Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found })
} else {
None

View file

@ -78,7 +78,7 @@ fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String {
.tcx
.sess
.source_map()
.span_to_snippet(c.value.span)
.span_to_snippet(c.span())
.unwrap_or_else(|_| "_".into()),
GenericArg::Infer(_) => String::from("_"),
})

View file

@ -912,6 +912,7 @@ impl<'hir> Map<'hir> {
Node::Field(field) => field.span,
Node::AnonConst(constant) => constant.span,
Node::ConstBlock(constant) => self.body(constant.body).value.span,
Node::ConstArg(const_arg) => const_arg.span(),
Node::Expr(expr) => expr.span,
Node::ExprField(field) => field.span,
Node::Stmt(stmt) => stmt.span,
@ -962,7 +963,8 @@ impl<'hir> Map<'hir> {
/// Returns the HirId of `N` in `struct Foo<const N: usize = { ... }>` when
/// called with the HirId for the `{ ... }` anon const
pub fn opt_const_param_default_param_def_id(self, anon_const: HirId) -> Option<LocalDefId> {
match self.tcx.parent_hir_node(anon_const) {
let const_arg = self.tcx.parent_hir_id(anon_const);
match self.tcx.parent_hir_node(const_arg) {
Node::GenericParam(GenericParam {
def_id: param_id,
kind: GenericParamKind::Const { .. },
@ -1182,6 +1184,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
}
Node::AnonConst(_) => node_str("const"),
Node::ConstBlock(_) => node_str("const"),
Node::ConstArg(_) => node_str("const"),
Node::Expr(_) => node_str("expr"),
Node::ExprField(_) => node_str("expr field"),
Node::Stmt(_) => node_str("stmt"),

View file

@ -4,9 +4,9 @@ use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisita
use either::Either;
use rustc_data_structures::intern::Interned;
use rustc_error_messages::MultiSpan;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self as hir, HirId};
use rustc_macros::HashStable;
use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
use tracing::{debug, instrument};
@ -183,16 +183,55 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
}
}
/// In some cases, [`hir::ConstArg`]s that are being used in the type system
/// through const generics need to have their type "fed" to them
/// using the query system.
///
/// Use this enum with [`Const::from_const_arg`] to instruct it with the
/// desired behavior.
#[derive(Debug, Clone, Copy)]
pub enum FeedConstTy {
/// Feed the type.
///
/// The `DefId` belongs to the const param that we are supplying
/// this (anon) const arg to.
Param(DefId),
/// Don't feed the type.
No,
}
impl<'tcx> Const<'tcx> {
/// Convert a [`hir::ConstArg`] to a [`ty::Const`](Self).
#[instrument(skip(tcx), level = "debug")]
pub fn from_const_arg(
tcx: TyCtxt<'tcx>,
const_arg: &'tcx hir::ConstArg<'tcx>,
feed: FeedConstTy,
) -> Self {
if let FeedConstTy::Param(param_def_id) = feed
&& let hir::ConstArgKind::Anon(anon) = &const_arg.kind
{
tcx.feed_anon_const_type(anon.def_id, tcx.type_of(param_def_id));
}
match const_arg.kind {
hir::ConstArgKind::Path(qpath) => {
// FIXME(min_generic_const_args): for now only params are lowered to ConstArgKind::Path
Self::from_param(tcx, qpath, const_arg.hir_id)
}
hir::ConstArgKind::Anon(anon) => Self::from_anon_const(tcx, anon.def_id),
}
}
/// Literals and const generic parameters are eagerly converted to a constant, everything else
/// becomes `Unevaluated`.
#[instrument(skip(tcx), level = "debug")]
pub fn from_anon_const(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Self {
let body_id = match tcx.hir_node_by_def_id(def) {
hir::Node::AnonConst(ac) => ac.body,
_ => span_bug!(
node => span_bug!(
tcx.def_span(def.to_def_id()),
"from_anon_const can only process anonymous constants"
"from_anon_const can only process anonymous constants, not {node:?}"
),
};
@ -201,7 +240,7 @@ impl<'tcx> Const<'tcx> {
let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic");
match Self::try_from_lit_or_param(tcx, ty, expr) {
match Self::try_from_lit(tcx, ty, expr) {
Some(v) => v,
None => ty::Const::new_unevaluated(
tcx,
@ -213,12 +252,36 @@ impl<'tcx> Const<'tcx> {
}
}
/// Lower a const param to a [`Const`].
///
/// IMPORTANT: `qpath` must be a const param, otherwise this will panic
fn from_param(tcx: TyCtxt<'tcx>, qpath: hir::QPath<'tcx>, hir_id: HirId) -> Self {
let hir::QPath::Resolved(_, &hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. }) =
qpath
else {
span_bug!(qpath.span(), "non-param {qpath:?} passed to Const::from_param")
};
match tcx.named_bound_var(hir_id) {
Some(rbv::ResolvedArg::EarlyBound(_)) => {
// Find the name and index of the const parameter by indexing the generics of
// the parent item and construct a `ParamConst`.
let item_def_id = tcx.parent(def_id);
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id];
let name = tcx.item_name(def_id);
ty::Const::new_param(tcx, ty::ParamConst::new(index, name))
}
Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index))
}
Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar),
arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id),
}
}
#[instrument(skip(tcx), level = "debug")]
fn try_from_lit_or_param(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
) -> Option<Self> {
fn try_from_lit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, expr: &'tcx hir::Expr<'tcx>) -> Option<Self> {
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
let expr = match &expr.kind {
@ -251,34 +314,15 @@ impl<'tcx> Const<'tcx> {
}
}
// FIXME(const_generics): We currently have to special case parameters because `min_const_generics`
// does not provide the parents generics to anonymous constants. We still allow generic const
// parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to
// ever try to instantiate the generic parameters in their bodies.
match expr.kind {
hir::ExprKind::Path(hir::QPath::Resolved(
_,
&hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. },
)) => {
match tcx.named_bound_var(expr.hir_id) {
Some(rbv::ResolvedArg::EarlyBound(_)) => {
// Find the name and index of the const parameter by indexing the generics of
// the parent item and construct a `ParamConst`.
let item_def_id = tcx.parent(def_id);
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id];
let name = tcx.item_name(def_id);
Some(ty::Const::new_param(tcx, ty::ParamConst::new(index, name)))
}
Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
Some(ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index)))
}
Some(rbv::ResolvedArg::Error(guar)) => Some(ty::Const::new_error(tcx, guar)),
arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id),
}
}
_ => None,
if let hir::ExprKind::Path(hir::QPath::Resolved(
_,
&hir::Path { res: Res::Def(DefKind::ConstParam, _), .. },
)) = expr.kind
{
span_bug!(expr.span, "try_from_lit: received const param which shouldn't be possible")
}
None
}
#[inline]
@ -483,15 +527,15 @@ pub fn const_param_default<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
let default_def_id = match tcx.hir_node_by_def_id(def_id) {
let default_ct = match tcx.hir_node_by_def_id(def_id) {
hir::Node::GenericParam(hir::GenericParam {
kind: hir::GenericParamKind::Const { default: Some(ac), .. },
kind: hir::GenericParamKind::Const { default: Some(ct), .. },
..
}) => ac.def_id,
}) => ct,
_ => span_bug!(
tcx.def_span(def_id),
"`const_param_default` expected a generic parameter with a constant"
),
};
ty::EarlyBinder::bind(Const::from_anon_const(tcx, default_def_id))
ty::EarlyBinder::bind(Const::from_const_arg(tcx, default_ct, FeedConstTy::No))
}

View file

@ -86,7 +86,7 @@ pub use self::closure::{
CAPTURE_STRUCT_LOCAL,
};
pub use self::consts::{
Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree,
Const, ConstInt, ConstKind, Expr, ExprKind, FeedConstTy, ScalarInt, UnevaluatedConst, ValTree,
};
pub use self::context::{
tls, CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift,

View file

@ -607,7 +607,9 @@ impl<'a, V> ::std::ops::Index<HirId> for LocalTableInContext<'a, V> {
type Output = V;
fn index(&self, key: HirId) -> &V {
self.get(key).expect("LocalTableInContext: key not found")
self.get(key).unwrap_or_else(|| {
bug!("LocalTableInContext({:?}): key {:?} not found", self.hir_owner, key)
})
}
}

View file

@ -452,7 +452,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
match ga {
hir::GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
hir::GenericArg::Type(ty) => self.visit_ty(ty),
hir::GenericArg::Const(ct) => self.visit_anon_const(&ct.value),
hir::GenericArg::Const(ct) => self.visit_const_arg(ct),
hir::GenericArg::Infer(inf) => self.visit_infer(inf),
}
}

View file

@ -312,8 +312,19 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
}
fn visit_anon_const(&mut self, constant: &'a AnonConst) {
let def = self.create_def(constant.id, kw::Empty, DefKind::AnonConst, constant.value.span);
self.with_parent(def, |this| visit::walk_anon_const(this, constant));
// HACK(min_generic_const_args): don't create defs for anon consts if we think they will
// later be turned into ConstArgKind::Path's. because this is before resolve is done, we
// may accidentally identify a construction of a unit struct as a param and not create a
// def. we'll then create a def later in ast lowering in this case. the parent of nested
// items will be messed up, but that's ok because there can't be any if we're just looking
// for bare idents.
if constant.value.is_potential_trivial_const_arg() {
visit::walk_anon_const(self, constant)
} else {
let def =
self.create_def(constant.id, kw::Empty, DefKind::AnonConst, constant.value.span);
self.with_parent(def, |this| visit::walk_anon_const(this, constant));
}
}
fn visit_expr(&mut self, expr: &'a Expr) {

View file

@ -672,9 +672,21 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
self.require_sized(subty, ObligationCauseCode::SliceOrArrayElem);
}
ty::Array(subty, _) => {
ty::Array(subty, len) => {
self.require_sized(subty, ObligationCauseCode::SliceOrArrayElem);
// Note that we handle the len is implicitly checked while walking `arg`.
// Note that the len being WF is implicitly checked while visiting.
// Here we just check that it's of type usize.
let cause = self.cause(ObligationCauseCode::Misc);
self.out.push(traits::Obligation::with_depth(
tcx,
cause,
self.recursion_depth,
self.param_env,
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(
len,
tcx.types.usize,
))),
));
}
ty::Pat(subty, _) => {

View file

@ -285,10 +285,17 @@ fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) ->
}
pub(crate) fn clean_const<'tcx>(
constant: &hir::ConstArg<'_>,
constant: &hir::ConstArg<'tcx>,
_cx: &mut DocContext<'tcx>,
) -> Constant {
Constant { kind: ConstantKind::Anonymous { body: constant.value.body } }
match &constant.kind {
hir::ConstArgKind::Path(qpath) => {
Constant { kind: ConstantKind::Path { path: qpath_to_string(&qpath).into() } }
}
hir::ConstArgKind::Anon(anon) => {
Constant { kind: ConstantKind::Anonymous { body: anon.body } }
}
}
}
pub(crate) fn clean_middle_const<'tcx>(
@ -431,7 +438,7 @@ fn clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Te
match term {
hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)),
hir::Term::Const(c) => Term::Constant(clean_middle_const(
ty::Binder::dummy(ty::Const::from_anon_const(cx.tcx, c.def_id)),
ty::Binder::dummy(ty::Const::from_const_arg(cx.tcx, c, ty::FeedConstTy::No)),
cx,
)),
}
@ -633,8 +640,9 @@ fn clean_generic_param<'tcx>(
param.name.ident().name,
GenericParamDefKind::Const {
ty: Box::new(clean_ty(ty, cx)),
default: default
.map(|ct| Box::new(ty::Const::from_anon_const(cx.tcx, ct.def_id).to_string())),
default: default.map(|ct| {
Box::new(ty::Const::from_const_arg(cx.tcx, ct, ty::FeedConstTy::No).to_string())
}),
synthetic,
},
),
@ -1820,7 +1828,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
TyKind::Array(ty, ref length) => {
let length = match length {
hir::ArrayLen::Infer(..) => "_".to_string(),
hir::ArrayLen::Body(anon_const) => {
hir::ArrayLen::Body(const_arg) => {
// NOTE(min_const_generics): We can't use `const_eval_poly` for constants
// as we currently do not supply the parent generics to anonymous constants
// but do allow `ConstKind::Param`.
@ -1828,9 +1836,18 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
// `const_eval_poly` tries to first substitute generic parameters which
// results in an ICE while manually constructing the constant and using `eval`
// does nothing for `ConstKind::Param`.
let ct = ty::Const::from_anon_const(cx.tcx, anon_const.def_id);
let param_env = cx.tcx.param_env(anon_const.def_id);
print_const(cx, ct.normalize(cx.tcx, param_env))
let ct = ty::Const::from_const_arg(cx.tcx, const_arg, ty::FeedConstTy::No);
let ct = if let hir::ConstArgKind::Anon(hir::AnonConst { def_id, .. }) =
const_arg.kind
{
// Only anon consts can implicitly capture params.
// FIXME: is this correct behavior?
let param_env = cx.tcx.param_env(*def_id);
ct.normalize(cx.tcx, param_env)
} else {
ct
};
print_const(cx, ct)
}
};

View file

@ -2395,6 +2395,9 @@ pub(crate) enum ConstantKind {
/// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified
/// by a DefId. So this field must be different from `Extern`.
TyConst { expr: Box<str> },
/// A constant that is just a path (i.e., referring to a const param, free const, etc.).
// FIXME: this is an unfortunate representation. rustdoc's logic around consts needs to be improved.
Path { path: Box<str> },
/// A constant (expression) that's not an item or associated item. These are usually found
/// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also
/// used to define explicit discriminant values for enum variants.
@ -2423,6 +2426,7 @@ impl ConstantKind {
pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
match *self {
ConstantKind::TyConst { ref expr } => expr.to_string(),
ConstantKind::Path { ref path } => path.to_string(),
ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
rendered_const(tcx, tcx.hir().body(body), tcx.hir().body_owner_def_id(body))
@ -2432,7 +2436,9 @@ impl ConstantKind {
pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
match *self {
ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None,
ConstantKind::TyConst { .. }
| ConstantKind::Path { .. }
| ConstantKind::Anonymous { .. } => None,
ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
print_evaluated_const(tcx, def_id, true, true)
}
@ -2441,7 +2447,9 @@ impl ConstantKind {
pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
match *self {
ConstantKind::TyConst { .. } | ConstantKind::Extern { .. } => false,
ConstantKind::TyConst { .. }
| ConstantKind::Extern { .. }
| ConstantKind::Path { .. } => false,
ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
is_literal_expr(tcx, body.hir_id)
}

View file

@ -106,13 +106,12 @@ fn might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
///
/// This is a fail-safe to a case where even the `is_from_proc_macro` is unable to determain the
/// correct result.
fn repeat_expr_might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
let ExprKind::Repeat(_, ArrayLen::Body(anon_const)) = expr.kind else {
fn repeat_expr_might_be_expanded<'tcx>(expr: &Expr<'tcx>) -> bool {
let ExprKind::Repeat(_, ArrayLen::Body(len_ct)) = expr.kind else {
return false;
};
let len_span = cx.tcx.def_span(anon_const.def_id);
!expr.span.contains(len_span)
!expr.span.contains(len_ct.span())
}
expr.span.from_expansion() || is_from_proc_macro(cx, expr) || repeat_expr_might_be_expanded(cx, expr)
expr.span.from_expansion() || is_from_proc_macro(cx, expr) || repeat_expr_might_be_expanded(expr)
}

View file

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::has_repr_attr;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Const;
use rustc_middle::ty::{Const, FeedConstTy};
use rustc_session::declare_lint_pass;
declare_clippy_lint! {
@ -53,14 +53,14 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
}
}
fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
fn is_struct_with_trailing_zero_sized_array<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool {
if let ItemKind::Struct(data, _) = &item.kind
// First check if last field is an array
&& let Some(last_field) = data.fields().last()
&& let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind
// Then check if that array is zero-sized
&& let length = Const::from_anon_const(cx.tcx, length.def_id)
&& let length = Const::from_const_arg(cx.tcx, length, FeedConstTy::No)
&& let length = length.try_eval_target_usize(cx.tcx, cx.param_env)
&& let Some(length) = length
{

View file

@ -5,10 +5,9 @@ use clippy_utils::{get_attr, higher};
use rustc_ast::ast::{LitFloatType, LitKind};
use rustc_ast::LitIntType;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_hir::{
ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, CoroutineKind, ExprKind, FnRetTy, HirId, Lit, PatKind,
QPath, StmtKind, TyKind,
self as hir, ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind,
ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::declare_lint_pass;
@ -270,6 +269,21 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
}
}
fn const_arg(&self, const_arg: &Binding<&ConstArg<'_>>) {
match const_arg.value.kind {
ConstArgKind::Path(ref qpath) => {
bind!(self, qpath);
chain!(self, "let ConstArgKind::Path(ref {qpath}) = {const_arg}.kind");
self.qpath(qpath);
},
ConstArgKind::Anon(anon_const) => {
bind!(self, anon_const);
chain!(self, "let ConstArgKind::Anon({anon_const}) = {const_arg}.kind");
self.body(field!(anon_const.body));
},
}
}
fn lit(&self, lit: &Binding<&Lit>) {
let kind = |kind| chain!(self, "let LitKind::{kind} = {lit}.node");
macro_rules! kind {
@ -602,10 +616,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
self.expr(value);
match length.value {
ArrayLen::Infer(..) => chain!(self, "let ArrayLen::Infer(..) = length"),
ArrayLen::Body(anon_const) => {
bind!(self, anon_const);
chain!(self, "let ArrayLen::Body({anon_const}) = {length}");
self.body(field!(anon_const.body));
ArrayLen::Body(const_arg) => {
bind!(self, const_arg);
chain!(self, "let ArrayLen::Body({const_arg}) = {length}");
self.const_arg(const_arg);
},
}
},

View file

@ -7,9 +7,9 @@ use rustc_data_structures::fx::FxHasher;
use rustc_hir::def::Res;
use rustc_hir::MatchSource::TryDesugar;
use rustc_hir::{
ArrayLen, AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy,
GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatField,
PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind,
ArrayLen, AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr,
ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime,
LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind,
};
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::LateContext;
@ -227,7 +227,7 @@ impl HirEqInterExpr<'_, '_, '_> {
pub fn eq_array_length(&mut self, left: ArrayLen<'_>, right: ArrayLen<'_>) -> bool {
match (left, right) {
(ArrayLen::Infer(..), ArrayLen::Infer(..)) => true,
(ArrayLen::Body(l_ct), ArrayLen::Body(r_ct)) => self.eq_body(l_ct.body, r_ct.body),
(ArrayLen::Body(l_ct), ArrayLen::Body(r_ct)) => self.eq_const_arg(l_ct, r_ct),
(_, _) => false,
}
}
@ -411,7 +411,7 @@ impl HirEqInterExpr<'_, '_, '_> {
fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool {
match (left, right) {
(GenericArg::Const(l), GenericArg::Const(r)) => self.eq_body(l.value.body, r.value.body),
(GenericArg::Const(l), GenericArg::Const(r)) => self.eq_const_arg(l, r),
(GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt),
(GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty, r_ty),
(GenericArg::Infer(l_inf), GenericArg::Infer(r_inf)) => self.eq_ty(&l_inf.to_ty(), &r_inf.to_ty()),
@ -419,6 +419,17 @@ impl HirEqInterExpr<'_, '_, '_> {
}
}
fn eq_const_arg(&mut self, left: &ConstArg<'_>, right: &ConstArg<'_>) -> bool {
match (&left.kind, &right.kind) {
(ConstArgKind::Path(l_p), ConstArgKind::Path(r_p)) => self.eq_qpath(l_p, r_p),
(ConstArgKind::Anon(l_an), ConstArgKind::Anon(r_an)) => self.eq_body(l_an.body, r_an.body),
// Use explicit match for now since ConstArg is undergoing flux.
(ConstArgKind::Path(..), ConstArgKind::Anon(..)) | (ConstArgKind::Anon(..), ConstArgKind::Path(..)) => {
false
},
}
}
fn eq_lifetime(left: &Lifetime, right: &Lifetime) -> bool {
left.res == right.res
}
@ -1123,7 +1134,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
pub fn hash_array_length(&mut self, length: ArrayLen<'_>) {
match length {
ArrayLen::Infer(..) => {},
ArrayLen::Body(anon_const) => self.hash_body(anon_const.body),
ArrayLen::Body(ct) => self.hash_const_arg(ct),
}
}
@ -1134,12 +1145,19 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
self.maybe_typeck_results = old_maybe_typeck_results;
}
fn hash_const_arg(&mut self, const_arg: &ConstArg<'_>) {
match &const_arg.kind {
ConstArgKind::Path(path) => self.hash_qpath(path),
ConstArgKind::Anon(anon) => self.hash_body(anon.body),
}
}
fn hash_generic_args(&mut self, arg_list: &[GenericArg<'_>]) {
for arg in arg_list {
match *arg {
GenericArg::Lifetime(l) => self.hash_lifetime(l),
GenericArg::Type(ty) => self.hash_ty(ty),
GenericArg::Const(ref ca) => self.hash_body(ca.value.body),
GenericArg::Const(ref ca) => self.hash_const_arg(ca),
GenericArg::Infer(ref inf) => self.hash_ty(&inf.to_ty()),
}
}

View file

@ -102,11 +102,11 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
use rustc_hir::{
self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstContext,
Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind,
ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat,
PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef,
TyKind, UnOp,
self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind,
ConstContext, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem,
ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode,
Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef,
TraitRef, TyKind, UnOp,
};
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::{LateContext, Level, Lint, LintContext};
@ -904,7 +904,8 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
},
ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),
ExprKind::Repeat(x, ArrayLen::Body(len)) => {
if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind
if let ConstArgKind::Anon(anon_const) = len.kind
&& let ExprKind::Lit(const_lit) = cx.tcx.hir().body(anon_const.body).value.kind
&& let LitKind::Int(v, _) = const_lit.node
&& v <= 32
&& is_default_equivalent(cx, x)
@ -933,7 +934,8 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &
}) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String),
ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec),
ExprKind::Repeat(_, ArrayLen::Body(len)) => {
if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind
if let ConstArgKind::Anon(anon_const) = len.kind
&& let ExprKind::Lit(const_lit) = cx.tcx.hir().body(anon_const.body).value.kind
&& let LitKind::Int(v, _) = const_lit.node
{
return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec);

View file

@ -1,7 +1,8 @@
if let ExprKind::Repeat(value, length) = expr.kind
&& let ExprKind::Lit(ref lit) = value.kind
&& let LitKind::Int(1, LitIntType::Unsigned(UintTy::U8)) = lit.node
&& let ArrayLen::Body(anon_const) = length
&& let ArrayLen::Body(const_arg) = length
&& let ConstArgKind::Anon(anon_const) = const_arg.kind
&& expr1 = &cx.tcx.hir().body(anon_const.body).value
&& let ExprKind::Lit(ref lit1) = expr1.kind
&& let LitKind::Int(5, LitIntType::Unsuffixed) = lit1.node

View file

@ -193,5 +193,11 @@ error: this ident consists of a single char
LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 {
| ^
error: aborting due to 32 previous errors
error: this ident consists of a single char
--> tests/ui/min_ident_chars.rs:93:41
|
LL | struct Array<T, const N: usize>([T; N]);
| ^
error: aborting due to 33 previous errors

11
tests/crashes/127009.rs Normal file
View file

@ -0,0 +1,11 @@
//@ known-bug: #127009
#![feature(non_lifetime_binders)]
fn b()
where
for<const C: usize> [(); C]: Copy,
{
}
fn main() {}

View file

@ -33,7 +33,7 @@ fn test_stable_mir() -> ControlFlow<()> {
// Get all items and split generic vs monomorphic items.
let (generic, mono): (Vec<_>, Vec<_>) =
items.into_iter().partition(|item| item.requires_monomorphization());
assert_eq!(mono.len(), 4, "Expected 2 mono functions and one constant");
assert_eq!(mono.len(), 3, "Expected 3 mono functions");
assert_eq!(generic.len(), 2, "Expected 2 generic functions");
// For all monomorphic items, get the correspondent instances.

View file

@ -5,9 +5,7 @@
#![feature(with_negative_coherence)]
trait Trait {}
impl<const N: u8> Trait for [(); N] {}
//~^ ERROR: mismatched types
impl<const N: i8> Trait for [(); N] {}
//~^ ERROR: mismatched types
//~| ERROR: conflicting implementations of trait `Trait`
//~^ ERROR: conflicting implementations of trait `Trait`
fn main() {}

View file

@ -1,25 +1,11 @@
error[E0119]: conflicting implementations of trait `Trait` for type `[(); _]`
--> $DIR/generic_const_type_mismatch.rs:9:1
--> $DIR/generic_const_type_mismatch.rs:8:1
|
LL | impl<const N: u8> Trait for [(); N] {}
| ----------------------------------- first implementation here
LL |
LL | impl<const N: i8> Trait for [(); N] {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[(); _]`
error[E0308]: mismatched types
--> $DIR/generic_const_type_mismatch.rs:7:34
|
LL | impl<const N: u8> Trait for [(); N] {}
| ^ expected `usize`, found `u8`
error: aborting due to 1 previous error
error[E0308]: mismatched types
--> $DIR/generic_const_type_mismatch.rs:9:34
|
LL | impl<const N: i8> Trait for [(); N] {}
| ^ expected `usize`, found `i8`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0119, E0308.
For more information about an error, try `rustc --explain E0119`.
For more information about this error, try `rustc --explain E0119`.

View file

@ -6,7 +6,7 @@ trait Q {
}
impl<const N: u64> Q for [u8; N] {
//~^ ERROR mismatched types
//~^ ERROR: the constant `N` is not of type `usize`
const ASSOC: usize = 1;
}

View file

@ -1,3 +1,9 @@
error: the constant `N` is not of type `usize`
--> $DIR/bad-subst-const-kind.rs:8:26
|
LL | impl<const N: u64> Q for [u8; N] {
| ^^^^^^^ expected `usize`, found `u64`
error: the constant `13` is not of type `u64`
--> $DIR/bad-subst-const-kind.rs:13:24
|
@ -12,12 +18,5 @@ LL | impl<const N: u64> Q for [u8; N] {
| |
| unsatisfied trait bound introduced here
error[E0308]: mismatched types
--> $DIR/bad-subst-const-kind.rs:8:31
|
LL | impl<const N: u64> Q for [u8; N] {
| ^ expected `usize`, found `u64`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -7,7 +7,7 @@ trait Q {
impl<const N: u64> Q for [u8; N] {}
//~^ ERROR not all trait items implemented
//~| ERROR mismatched types
//~| ERROR the constant `N` is not of type `usize`
pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {}
//~^ ERROR the constant `13` is not of type `u64`

View file

@ -1,3 +1,9 @@
error: the constant `N` is not of type `usize`
--> $DIR/type_mismatch.rs:8:26
|
LL | impl<const N: u64> Q for [u8; N] {}
| ^^^^^^^ expected `usize`, found `u64`
error[E0046]: not all trait items implemented, missing: `ASSOC`
--> $DIR/type_mismatch.rs:8:1
|
@ -29,12 +35,6 @@ LL | pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {}
| |
| implicitly returns `()` as its body has no tail or `return` expression
error[E0308]: mismatched types
--> $DIR/type_mismatch.rs:8:31
|
LL | impl<const N: u64> Q for [u8; N] {}
| ^ expected `usize`, found `u64`
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0046, E0308.

View file

@ -25,8 +25,8 @@ mod v20 {
}
impl<const v10: usize> v17<v10, v2> {
//~^ ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#1}
//~| ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#1}
//~^ ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0}
//~| ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0}
pub const fn v21() -> v18 {
//~^ ERROR cannot find type `v18` in this scope
v18 { _p: () }

View file

@ -72,13 +72,13 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
LL + #![feature(adt_const_params)]
|
error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#1}
error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0}
--> $DIR/unevaluated-const-ice-119731.rs:27:37
|
LL | impl<const v10: usize> v17<v10, v2> {
| ^^
error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#1}
error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0}
--> $DIR/unevaluated-const-ice-119731.rs:27:37
|
LL | impl<const v10: usize> v17<v10, v2> {

View file

@ -1,26 +1,32 @@
error[E0284]: type annotations needed: cannot satisfy `the constant `name_len::<T>()` can be evaluated`
--> $DIR/issue-88119.rs:21:5
error[E0284]: type annotations needed: cannot normalize `<&T as ConstName>::{constant#0}`
--> $DIR/issue-88119.rs:19:49
|
LL | impl<T: ?Sized + ConstName> const ConstName for &T
| ^^ cannot normalize `<&T as ConstName>::{constant#0}`
|
note: required for `&T` to implement `ConstName`
--> $DIR/issue-88119.rs:19:35
|
LL | impl<T: ?Sized + ConstName> const ConstName for &T
| ^^^^^^^^^ ^^
LL | where
LL | [(); name_len::<T>()]:,
| ^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `name_len::<T>()` can be evaluated`
|
note: required by a bound in `<&T as ConstName>`
--> $DIR/issue-88119.rs:21:10
|
LL | [(); name_len::<T>()]:,
| ^^^^^^^^^^^^^^^ required by this bound in `<&T as ConstName>`
| --------------------- unsatisfied trait bound introduced here
error[E0284]: type annotations needed: cannot satisfy `the constant `name_len::<T>()` can be evaluated`
--> $DIR/issue-88119.rs:28:5
error[E0284]: type annotations needed: cannot normalize `<&mut T as ConstName>::{constant#0}`
--> $DIR/issue-88119.rs:26:49
|
LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
| ^^^^^^ cannot normalize `<&mut T as ConstName>::{constant#0}`
|
note: required for `&mut T` to implement `ConstName`
--> $DIR/issue-88119.rs:26:35
|
LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
| ^^^^^^^^^ ^^^^^^
LL | where
LL | [(); name_len::<T>()]:,
| ^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `name_len::<T>()` can be evaluated`
|
note: required by a bound in `<&mut T as ConstName>`
--> $DIR/issue-88119.rs:28:10
|
LL | [(); name_len::<T>()]:,
| ^^^^^^^^^^^^^^^ required by this bound in `<&mut T as ConstName>`
| --------------------- unsatisfied trait bound introduced here
error: aborting due to 2 previous errors

View file

@ -19,6 +19,8 @@ fn bar<const N: usize>() {}
fn foo<const N: usize>() {
bar::<{ [1; N] }>();
//~^ ERROR: generic parameters may not be used in const operations
bar::<{ [1; { N + 1 }] }>();
//~^ ERROR: generic parameters may not be used in const operations
}
fn main() {}

View file

@ -7,5 +7,14 @@ LL | bar::<{ [1; N] }>();
= help: const parameters may only be used as standalone arguments, i.e. `N`
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
error: aborting due to 1 previous error
error: generic parameters may not be used in const operations
--> $DIR/repeat_expr_hack_gives_right_generics.rs:22:19
|
LL | bar::<{ [1; { N + 1 }] }>();
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `N`
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
error: aborting due to 2 previous errors

View file

@ -10,11 +10,10 @@ fn foo<const W: usize, const H: usize>(v: [[u32;H+1]; W]) -> [[u32; W+1]; H] {
}
fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] {
//~^ ERROR mismatched types
//~| ERROR mismatched types
//~^ ERROR the constant `W` is not of type `usize`
unsafe {
std::mem::transmute(v)
//~^ ERROR cannot transmute between types
//~^ ERROR the constant `W` is not of type `usize`
}
}

View file

@ -1,3 +1,9 @@
error: the constant `W` is not of type `usize`
--> $DIR/transmute-fail.rs:12:42
|
LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] {
| ^^^^^^^^^^^^^ expected `usize`, found `bool`
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/transmute-fail.rs:7:5
|
@ -7,17 +13,14 @@ LL | std::mem::transmute(v)
= note: source type: `[[u32; H+1]; W]` (size can vary because of [u32; H+1])
= note: target type: `[[u32; W+1]; H]` (size can vary because of [u32; W+1])
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/transmute-fail.rs:16:5
error: the constant `W` is not of type `usize`
--> $DIR/transmute-fail.rs:15:5
|
LL | std::mem::transmute(v)
| ^^^^^^^^^^^^^^^^^^^
|
= note: source type: `[[u32; H]; W]` (size can vary because of [u32; H])
= note: target type: `[[u32; W]; H]` (size can vary because of [u32; W])
| ^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/transmute-fail.rs:23:5
--> $DIR/transmute-fail.rs:22:5
|
LL | std::mem::transmute(v)
| ^^^^^^^^^^^^^^^^^^^
@ -26,7 +29,7 @@ LL | std::mem::transmute(v)
= note: target type: `[u32; W * H * H]` (this type does not have a fixed size)
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/transmute-fail.rs:30:5
--> $DIR/transmute-fail.rs:29:5
|
LL | std::mem::transmute(v)
| ^^^^^^^^^^^^^^^^^^^
@ -35,7 +38,7 @@ LL | std::mem::transmute(v)
= note: target type: `[[[u32; 9999999]; 777777777]; 8888888]` (values of the type `[[u32; 9999999]; 777777777]` are too big for the current architecture)
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/transmute-fail.rs:37:5
--> $DIR/transmute-fail.rs:36:5
|
LL | std::mem::transmute(v)
| ^^^^^^^^^^^^^^^^^^^
@ -44,7 +47,7 @@ LL | std::mem::transmute(v)
= note: target type: `[[u32; W]; H]` (size can vary because of [u32; W])
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/transmute-fail.rs:50:5
--> $DIR/transmute-fail.rs:49:5
|
LL | std::mem::transmute(v)
| ^^^^^^^^^^^^^^^^^^^
@ -53,7 +56,7 @@ LL | std::mem::transmute(v)
= note: target type: `[u32; W * H]` (this type does not have a fixed size)
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/transmute-fail.rs:57:5
--> $DIR/transmute-fail.rs:56:5
|
LL | std::mem::transmute(v)
| ^^^^^^^^^^^^^^^^^^^
@ -62,7 +65,7 @@ LL | std::mem::transmute(v)
= note: target type: `[[u32; W]; H]` (size can vary because of [u32; W])
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/transmute-fail.rs:66:5
--> $DIR/transmute-fail.rs:65:5
|
LL | std::mem::transmute(v)
| ^^^^^^^^^^^^^^^^^^^
@ -71,7 +74,7 @@ LL | std::mem::transmute(v)
= note: target type: `[u32; D * W * H]` (this type does not have a fixed size)
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/transmute-fail.rs:75:5
--> $DIR/transmute-fail.rs:74:5
|
LL | std::mem::transmute(v)
| ^^^^^^^^^^^^^^^^^^^
@ -80,7 +83,7 @@ LL | std::mem::transmute(v)
= note: target type: `[[u32; D * W]; H]` (size can vary because of [u32; D * W])
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/transmute-fail.rs:82:5
--> $DIR/transmute-fail.rs:81:5
|
LL | std::mem::transmute(v)
| ^^^^^^^^^^^^^^^^^^^
@ -89,7 +92,7 @@ LL | std::mem::transmute(v)
= note: target type: `[u8; L * 2]` (this type does not have a fixed size)
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/transmute-fail.rs:89:5
--> $DIR/transmute-fail.rs:88:5
|
LL | std::mem::transmute(v)
| ^^^^^^^^^^^^^^^^^^^
@ -98,7 +101,7 @@ LL | std::mem::transmute(v)
= note: target type: `[u16; L]` (this type does not have a fixed size)
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/transmute-fail.rs:96:5
--> $DIR/transmute-fail.rs:95:5
|
LL | std::mem::transmute(v)
| ^^^^^^^^^^^^^^^^^^^
@ -107,7 +110,7 @@ LL | std::mem::transmute(v)
= note: target type: `[[u8; 1]; L]` (this type does not have a fixed size)
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/transmute-fail.rs:105:5
--> $DIR/transmute-fail.rs:104:5
|
LL | std::mem::transmute(v)
| ^^^^^^^^^^^^^^^^^^^
@ -115,19 +118,6 @@ LL | std::mem::transmute(v)
= note: source type: `[[u32; 2 * H]; W + W]` (size can vary because of [u32; 2 * H])
= note: target type: `[[u32; W + W]; 2 * H]` (size can vary because of [u32; W + W])
error[E0308]: mismatched types
--> $DIR/transmute-fail.rs:12:53
|
LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] {
| ^ expected `usize`, found `bool`
error: aborting due to 14 previous errors
error[E0308]: mismatched types
--> $DIR/transmute-fail.rs:12:67
|
LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] {
| ^ expected `usize`, found `bool`
error: aborting due to 15 previous errors
Some errors have detailed explanations: E0308, E0512.
For more information about an error, try `rustc --explain E0308`.
For more information about this error, try `rustc --explain E0512`.

View file

@ -1,10 +1,10 @@
fn foo<const N: usize>() -> [u8; N] {
bar::<N>() //~ ERROR mismatched types
bar::<N>()
//~^ ERROR the constant `N` is not of type `u8`
}
fn bar<const N: u8>() -> [u8; N] {}
//~^ ERROR mismatched types
//~^ ERROR the constant `N` is not of type `usize`
//~| ERROR mismatched types
fn main() {}

View file

@ -1,3 +1,9 @@
error: the constant `N` is not of type `usize`
--> $DIR/type_mismatch.rs:6:26
|
LL | fn bar<const N: u8>() -> [u8; N] {}
| ^^^^^^^ expected `usize`, found `u8`
error: the constant `N` is not of type `u8`
--> $DIR/type_mismatch.rs:2:11
|
@ -18,18 +24,6 @@ LL | fn bar<const N: u8>() -> [u8; N] {}
| |
| implicitly returns `()` as its body has no tail or `return` expression
error[E0308]: mismatched types
--> $DIR/type_mismatch.rs:2:11
|
LL | bar::<N>()
| ^ expected `u8`, found `usize`
error[E0308]: mismatched types
--> $DIR/type_mismatch.rs:6:31
|
LL | fn bar<const N: u8>() -> [u8; N] {}
| ^ expected `usize`, found `u8`
error: aborting due to 4 previous errors
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -1,10 +1,10 @@
error[E0391]: cycle detected when simplifying constant for the type system `Foo::B::{constant#0}`
error[E0391]: cycle detected when simplifying constant for the type system `Foo::{constant#0}`
--> $DIR/issue-36163.rs:4:9
|
LL | B = A,
| ^
|
note: ...which requires const-evaluating + checking `Foo::B::{constant#0}`...
note: ...which requires const-evaluating + checking `Foo::{constant#0}`...
--> $DIR/issue-36163.rs:4:9
|
LL | B = A,
@ -19,7 +19,7 @@ note: ...which requires const-evaluating + checking `A`...
|
LL | const A: isize = Foo::B as isize;
| ^^^^^^^^^^^^^^^
= note: ...which again requires simplifying constant for the type system `Foo::B::{constant#0}`, completing the cycle
= note: ...which again requires simplifying constant for the type system `Foo::{constant#0}`, completing the cycle
note: cycle used when checking that `Foo` is well-formed
--> $DIR/issue-36163.rs:3:1
|

View file

@ -9,6 +9,5 @@ impl Fn(&isize) for Error {
//~^ ERROR associated function in `impl` without body
//~^^ ERROR method `foo` is not a member of trait `Fn` [E0407]
//~^^^ ERROR associated type `B` not found for `Self` [E0220]
//~| ERROR associated type `B` not found for `Self` [E0220]
}
fn main() {}

View file

@ -56,15 +56,7 @@ error[E0220]: associated type `B` not found for `Self`
LL | fn foo<const N: usize>(&self) -> Self::B<{ N }>;
| ^ help: `Self` has the following associated type: `Output`
error[E0220]: associated type `B` not found for `Self`
--> $DIR/issue-95023.rs:8:44
|
LL | fn foo<const N: usize>(&self) -> Self::B<{ N }>;
| ^ help: `Self` has the following associated type: `Output`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 8 previous errors
error: aborting due to 7 previous errors
Some errors have detailed explanations: E0046, E0183, E0220, E0229, E0277, E0407.
For more information about an error, try `rustc --explain E0046`.

View file

@ -4,20 +4,11 @@ error[E0284]: type annotations needed: cannot normalize `process<T>::{constant#0
LL | fn process<T: const Trait>(input: [(); T::make(2)]) -> [(); T::make(2)] {
| ^^^^^^^^^^^^^^^^ cannot normalize `process<T>::{constant#0}`
error[E0284]: type annotations needed: cannot satisfy `the constant `T::make(P)` can be evaluated`
--> $DIR/const-trait-bounds.rs:18:5
error[E0284]: type annotations needed: cannot normalize `Struct<T, P>::field::{constant#0}`
--> $DIR/const-trait-bounds.rs:20:12
|
LL | [u32; T::make(P)]:,
| ^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `T::make(P)` can be evaluated`
|
note: required by a bound in `Struct`
--> $DIR/const-trait-bounds.rs:18:11
|
LL | struct Struct<T: const Trait, const P: usize>
| ------ required by a bound in this struct
LL | where
LL | [u32; T::make(P)]:,
| ^^^^^^^^^^ required by this bound in `Struct`
LL | field: [u32; T::make(P)],
| ^^^^^^^^^^^^^^^^^ cannot normalize `Struct<T, P>::field::{constant#0}`
error[E0284]: type annotations needed: cannot normalize `process<T>::{constant#1}`
--> $DIR/const-trait-bounds.rs:13:5

View file

@ -14,6 +14,5 @@ struct Wrapper<const C: <i32 as Trait>::Type> {}
impl<const C: usize> Wrapper<C> {}
//~^ ERROR the constant `C` is not of type `<i32 as Trait>::Type`
//~^^ ERROR mismatched types
fn main() {}

View file

@ -20,17 +20,5 @@ note: required by a const generic parameter in `Wrapper`
LL | struct Wrapper<const C: <i32 as Trait>::Type> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this const generic parameter in `Wrapper`
error[E0308]: mismatched types
--> $DIR/default-proj-ty-as-type-of-const-issue-125757.rs:15:30
|
LL | impl<const C: usize> Wrapper<C> {}
| ^ expected associated type, found `usize`
|
= note: expected associated type `<i32 as Trait>::Type`
found type `usize`
= help: consider constraining the associated type `<i32 as Trait>::Type` to `usize`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error: aborting due to 2 previous errors
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -6,7 +6,6 @@
struct S<const L: usize>;
impl<const N: i32> Copy for S<N> {}
//~^ ERROR: mismatched types
impl<const M: usize> Copy for S<M> {}
//~^ ERROR: conflicting implementations of trait `Copy` for type `S<_>`

View file

@ -1,19 +1,11 @@
error[E0119]: conflicting implementations of trait `Copy` for type `S<_>`
--> $DIR/bad-const-wf-doesnt-specialize.rs:10:1
--> $DIR/bad-const-wf-doesnt-specialize.rs:9:1
|
LL | impl<const N: i32> Copy for S<N> {}
| -------------------------------- first implementation here
LL |
LL | impl<const M: usize> Copy for S<M> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>`
error[E0308]: mismatched types
--> $DIR/bad-const-wf-doesnt-specialize.rs:8:31
|
LL | impl<const N: i32> Copy for S<N> {}
| ^ expected `usize`, found `i32`
error: aborting due to 1 previous error
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0119, E0308.
For more information about an error, try `rustc --explain E0119`.
For more information about this error, try `rustc --explain E0119`.

View file

@ -123,15 +123,15 @@ hir-stats Lifetime 24 ( 0.3%) 1 24
hir-stats Mod 32 ( 0.4%) 1 32
hir-stats ExprField 40 ( 0.4%) 1 40
hir-stats TraitItemRef 56 ( 0.6%) 2 28
hir-stats GenericArg 64 ( 0.7%) 4 16
hir-stats - Type 16 ( 0.2%) 1
hir-stats - Lifetime 48 ( 0.5%) 3
hir-stats Local 64 ( 0.7%) 1 64
hir-stats Param 64 ( 0.7%) 2 32
hir-stats Body 72 ( 0.8%) 3 24
hir-stats InlineAsm 72 ( 0.8%) 1 72
hir-stats ImplItemRef 72 ( 0.8%) 2 36
hir-stats Arm 80 ( 0.9%) 2 40
hir-stats GenericArg 96 ( 1.1%) 4 24
hir-stats - Type 24 ( 0.3%) 1
hir-stats - Lifetime 72 ( 0.8%) 3
hir-stats FieldDef 96 ( 1.1%) 2 48
hir-stats Stmt 96 ( 1.1%) 3 32
hir-stats - Let 32 ( 0.4%) 1
@ -155,8 +155,8 @@ hir-stats Generics 560 ( 6.2%) 10 56
hir-stats Ty 720 ( 8.0%) 15 48
hir-stats - Ptr 48 ( 0.5%) 1
hir-stats - Ref 48 ( 0.5%) 1
hir-stats - Path 624 ( 6.9%) 13
hir-stats Expr 768 ( 8.5%) 12 64
hir-stats - Path 624 ( 7.0%) 13
hir-stats Expr 768 ( 8.6%) 12 64
hir-stats - Path 64 ( 0.7%) 1
hir-stats - Struct 64 ( 0.7%) 1
hir-stats - Match 64 ( 0.7%) 1
@ -174,5 +174,5 @@ hir-stats - Use 352 ( 3.9%) 4
hir-stats Path 1_240 (13.8%) 31 40
hir-stats PathSegment 1_920 (21.4%) 40 48
hir-stats ----------------------------------------------------------------
hir-stats Total 8_992
hir-stats Total 8_960
hir-stats

View file

@ -1,11 +0,0 @@
#![feature(non_lifetime_binders)]
//~^ WARN the feature `non_lifetime_binders` is incomplete
fn b()
where
for<const C: usize> [(); C]: Copy,
//~^ ERROR cannot capture late-bound const parameter in constant
{
}
fn main() {}

View file

@ -1,19 +0,0 @@
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/capture-late-ct-in-anon.rs:1:12
|
LL | #![feature(non_lifetime_binders)]
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
= note: `#[warn(incomplete_features)]` on by default
error: cannot capture late-bound const parameter in constant
--> $DIR/capture-late-ct-in-anon.rs:6:30
|
LL | for<const C: usize> [(); C]: Copy,
| -------------- ^
| |
| parameter defined here
error: aborting due to 1 previous error; 1 warning emitted

View file

@ -7,7 +7,6 @@ mod assert {
where
Dst: BikeshedIntrinsicFrom<Src, ASSUME_ALIGNMENT>, //~ ERROR cannot find type `Dst` in this scope
//~^ the constant `ASSUME_ALIGNMENT` is not of type `Assume`
//~| ERROR: mismatched types
{
}
}

View file

@ -13,13 +13,6 @@ LL | Dst: BikeshedIntrinsicFrom<Src, ASSUME_ALIGNMENT>,
note: required by a const generic parameter in `BikeshedIntrinsicFrom`
--> $SRC_DIR/core/src/mem/transmutability.rs:LL:COL
error[E0308]: mismatched types
--> $DIR/issue-101739-1.rs:8:41
|
LL | Dst: BikeshedIntrinsicFrom<Src, ASSUME_ALIGNMENT>,
| ^^^^^^^^^^^^^^^^ expected `Assume`, found `bool`
error: aborting due to 2 previous errors
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0308, E0412.
For more information about an error, try `rustc --explain E0308`.
For more information about this error, try `rustc --explain E0412`.

View file

@ -16,7 +16,7 @@ mod assert {
where
Dst: BikeshedIntrinsicFrom< //~ ERROR trait takes at most 2 generic arguments but 5 generic arguments were supplied
Src,
ASSUME_ALIGNMENT, //~ ERROR: mismatched types
ASSUME_ALIGNMENT,
ASSUME_LIFETIMES,
ASSUME_VALIDITY,
ASSUME_VISIBILITY,

View file

@ -9,13 +9,6 @@ LL | | ASSUME_VALIDITY,
LL | | ASSUME_VISIBILITY,
| |_____________________________- help: remove these generic arguments
error[E0308]: mismatched types
--> $DIR/issue-101739-2.rs:19:13
|
LL | ASSUME_ALIGNMENT,
| ^^^^^^^^^^^^^^^^ expected `Assume`, found `bool`
error: aborting due to 1 previous error
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0107, E0308.
For more information about an error, try `rustc --explain E0107`.
For more information about this error, try `rustc --explain E0107`.

View file

@ -5,7 +5,7 @@
trait Trait {
fn func<const N: u32>() -> [ (); N ]; //~ ERROR mismatched types
fn func<const N: u32>() -> [ (); N ]; //~ ERROR the constant `N` is not of type `usize`
}
struct S {}

View file

@ -4,11 +4,11 @@ error[E0308]: mismatched types
LL | fn func<const N: u32>() -> [ (); { () }] {
| ^^ expected `usize`, found `()`
error[E0308]: mismatched types
--> $DIR/const-in-impl-fn-return-type.rs:8:38
error: the constant `N` is not of type `usize`
--> $DIR/const-in-impl-fn-return-type.rs:8:32
|
LL | fn func<const N: u32>() -> [ (); N ];
| ^ expected `usize`, found `u32`
| ^^^^^^^^^ expected `usize`, found `u32`
error: aborting due to 2 previous errors