}
ExprKind::Repeat(ref expr, ref count) => {
let expr = self.lower_expr(expr);
- let count = self.lower_anon_const(count);
+ let count = self.lower_array_length(count);
hir::ExprKind::Repeat(expr, count)
}
ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
use rustc_index::vec::{Idx, IndexVec};
use rustc_query_system::ich::StableHashingContext;
use rustc_session::lint::LintBuffer;
+use rustc_session::parse::feature_err;
use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
use rustc_session::Session;
use rustc_span::hygiene::ExpnId;
))
}
TyKind::Array(ref ty, ref length) => {
- hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_anon_const(length))
+ hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length))
}
TyKind::Typeof(ref expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)),
TyKind::TraitObject(ref bounds, kind) => {
self.expr_block(block, AttrVec::new())
}
+ fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen {
+ match c.value.kind {
+ ExprKind::Underscore => {
+ if self.sess.features_untracked().generic_arg_infer {
+ hir::ArrayLen::Infer(self.lower_node_id(c.id), c.value.span)
+ } else {
+ feature_err(
+ &self.sess.parse_sess,
+ sym::generic_arg_infer,
+ c.value.span,
+ "using `_` for array lengths is unstable",
+ )
+ .emit();
+ hir::ArrayLen::Body(self.lower_anon_const(c))
+ }
+ }
+ _ => hir::ArrayLen::Body(self.lower_anon_const(c)),
+ }
+ }
+
fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
self.with_new_scopes(|this| hir::AnonConst {
hir_id: this.lower_node_id(c.id),
/// A literal.
pub type Lit = Spanned<LitKind>;
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
+pub enum ArrayLen {
+ Infer(HirId, Span),
+ Body(AnonConst),
+}
+
+impl ArrayLen {
+ pub fn hir_id(&self) -> HirId {
+ match self {
+ &ArrayLen::Infer(hir_id, _) | &ArrayLen::Body(AnonConst { hir_id, body: _ }) => hir_id,
+ }
+ }
+}
+
/// A constant (expression) that's not an item or associated item,
/// but needs its own `DefId` for type-checking, const-eval, etc.
/// These are usually found nested inside types (e.g., array lengths)
///
/// E.g., `[1; 5]`. The first expression is the element
/// to be repeated; the second is the number of times to repeat it.
- Repeat(&'hir Expr<'hir>, AnonConst),
+ Repeat(&'hir Expr<'hir>, ArrayLen),
/// A suspension point for generators (i.e., `yield <expr>`).
Yield(&'hir Expr<'hir>, YieldSource),
/// A variable length slice (i.e., `[T]`).
Slice(&'hir Ty<'hir>),
/// A fixed length array (i.e., `[T; n]`).
- Array(&'hir Ty<'hir>, AnonConst),
+ Array(&'hir Ty<'hir>, ArrayLen),
/// A raw pointer (i.e., `*const T` or `*mut T`).
Ptr(MutTy<'hir>),
/// A reference (i.e., `&'a T` or `&'a mut T`).
fn visit_pat(&mut self, p: &'v Pat<'v>) {
walk_pat(self, p)
}
+ fn visit_array_length(&mut self, len: &'v ArrayLen) {
+ walk_array_len(self, len)
+ }
fn visit_anon_const(&mut self, c: &'v AnonConst) {
walk_anon_const(self, c)
}
}
TyKind::Array(ref ty, ref length) => {
visitor.visit_ty(ty);
- visitor.visit_anon_const(length)
+ visitor.visit_array_length(length)
}
TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
for bound in bounds {
}
}
+pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) {
+ match len {
+ &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id),
+ ArrayLen::Body(c) => visitor.visit_anon_const(c),
+ }
+}
+
pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) {
visitor.visit_id(constant.hir_id);
visitor.visit_nested_body(constant.body);
ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const),
ExprKind::Repeat(ref element, ref count) => {
visitor.visit_expr(element);
- visitor.visit_anon_const(count)
+ visitor.visit_array_length(count)
}
ExprKind::Struct(ref qpath, fields, ref optional_base) => {
visitor.visit_qpath(qpath, expression.hir_id, expression.span);
self.word("[");
self.print_type(&ty);
self.word("; ");
- self.print_anon_const(length);
+ self.print_array_length(length);
self.word("]");
}
hir::TyKind::Typeof(ref e) => {
self.print_else(elseopt)
}
+ pub 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),
+ }
+ }
+
pub fn print_anon_const(&mut self, constant: &hir::AnonConst) {
self.ann.nested(self, Nested::Body(constant.body))
}
self.end()
}
- fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst) {
+ fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::ArrayLen) {
self.ibox(INDENT_UNIT);
self.word("[");
self.print_expr(element);
self.word_space(";");
- self.print_anon_const(count);
+ self.print_array_length(count);
self.word("]");
self.end()
}
ExprKind::ConstBlock { value }
}
// Now comes the rote stuff:
- hir::ExprKind::Repeat(ref v, ref count) => {
- let count_def_id = self.tcx.hir().local_def_id(count.hir_id);
- let count = ty::Const::from_anon_const(self.tcx, count_def_id);
+ hir::ExprKind::Repeat(ref v, _) => {
+ let ty = self.typeck_results().expr_ty(expr);
+ let count = match ty.kind() {
+ ty::Array(_, ct) => ct,
+ _ => span_bug!(expr.span, "unexpected repeat expr ty: {:?}", ty),
+ };
ExprKind::Repeat { value: self.mirror_expr(v), count }
}
}
intravisit::walk_qpath(self, path, t.hir_id, t.span);
}
- hir::TyKind::Array(ref ty, ref anon_const) => {
+ hir::TyKind::Array(ref ty, ref length) => {
self.visit_ty(ty);
let map = self.tcx.hir();
- self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
- v.visit_expr(&map.body(anon_const.body).value)
- });
+ match length {
+ // FIXME(generic_arg_infer): We probably want to
+ // output the inferred type here? :shrug:
+ hir::ArrayLen::Infer(..) => {}
+ hir::ArrayLen::Body(anon_const) => self
+ .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+ v.visit_expr(&map.body(anon_const.body).value)
+ }),
+ }
}
hir::TyKind::OpaqueDef(item_id, _) => {
let item = self.tcx.hir().item(item_id);
v.visit_expr(&body.value)
});
}
- hir::ExprKind::Repeat(ref expr, ref anon_const) => {
+ hir::ExprKind::Repeat(ref expr, ref length) => {
self.visit_expr(expr);
let map = self.tcx.hir();
- self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
- v.visit_expr(&map.body(anon_const.body).value)
- });
+ match length {
+ // FIXME(generic_arg_infer): We probably want to
+ // output the inferred type here? :shrug:
+ hir::ArrayLen::Infer(..) => {}
+ hir::ArrayLen::Body(anon_const) => self
+ .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+ v.visit_expr(&map.body(anon_const.body).value)
+ }),
+ }
}
// In particular, we take this branch for call and path expressions,
// where we'll index the idents involved just by continuing to walk.
let nested = bounds_to_string(&bounds);
Ok(text_sig(nested))
}
- hir::TyKind::Array(ref ty, ref anon_const) => {
+ hir::TyKind::Array(ref ty, ref length) => {
let nested_ty = ty.make(offset + 1, id, scx)?;
- let expr = id_to_string(&scx.tcx.hir(), anon_const.body.hir_id).replace('\n', " ");
+ let hir_id = match length {
+ &hir::ArrayLen::Infer(hir_id, _) => hir_id,
+ hir::ArrayLen::Body(anon_const) => anon_const.hir_id,
+ };
+ let expr = id_to_string(&scx.tcx.hir(), hir_id).replace('\n', " ");
let text = format!("[{}; {}]", nested_ty.text, expr);
Ok(replace_text(nested_ty, text))
}
GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
GenericParamDefKind::Const { .. },
) if tcx.type_of(param.def_id) == tcx.types.usize => {
- let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id));
+ let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id()));
if let Ok(snippet) = snippet {
err.span_suggestion(
arg.span(),
self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs))
}
hir::TyKind::Array(ref ty, ref length) => {
- let length_def_id = tcx.hir().local_def_id(length.hir_id);
- let length = ty::Const::from_anon_const(tcx, length_def_id);
+ let length = match length {
+ &hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span),
+ hir::ArrayLen::Body(constant) => {
+ let length_def_id = tcx.hir().local_def_id(constant.hir_id);
+ ty::Const::from_anon_const(tcx, length_def_id)
+ }
+ };
+
let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length));
self.normalize_ty(ast_ty.span, array_ty)
}
fn check_expr_repeat(
&self,
element: &'tcx hir::Expr<'tcx>,
- count: &'tcx hir::AnonConst,
+ count: &'tcx hir::ArrayLen,
expected: Expectation<'tcx>,
_expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
let tcx = self.tcx;
- let count = self.to_const(count);
+ let count = self.array_length_to_const(count);
let uty = match expected {
ExpectHasType(uty) => match *uty.kind() {
ty
}
+ pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> &'tcx ty::Const<'tcx> {
+ match length {
+ &hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span),
+ hir::ArrayLen::Body(anon_const) => self.to_const(anon_const),
+ }
+ }
+
pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
let c = ty::Const::from_anon_const(self.tcx, const_def_id);
sugg.push((span, format!(", {}", type_name)));
}
- let mut err = bad_placeholder_type(tcx, placeholder_types, kind);
+ let mut err = bad_placeholder(tcx, "type", placeholder_types, kind);
// Suggest, but only if it is not a function in const or static
if suggest {
///////////////////////////////////////////////////////////////////////////
// Utility types and common code for the above passes.
-fn bad_placeholder_type<'tcx>(
+fn bad_placeholder<'tcx>(
tcx: TyCtxt<'tcx>,
+ placeholder_kind: &'static str,
mut spans: Vec<Span>,
kind: &'static str,
) -> rustc_errors::DiagnosticBuilder<'tcx> {
tcx.sess,
spans.clone(),
E0121,
- "the type placeholder `_` is not allowed within types on item signatures for {}",
+ "the {} placeholder `_` is not allowed within types on item signatures for {}",
+ placeholder_kind,
kind
);
for span in spans {
_: Option<&ty::GenericParamDef>,
span: Span,
) -> &'tcx Const<'tcx> {
- bad_placeholder_type(self.tcx(), vec![span], "generic").emit();
+ bad_placeholder(self.tcx(), "const", vec![span], "generic").emit();
// Typeck doesn't expect erased regions to be returned from `type_of`.
let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match r {
ty::ReErased => self.tcx.lifetimes.re_static,
// `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(_, ref constant), .. })
- | Node::Variant(Variant { disr_expr: Some(ref constant), .. })
+ if constant.hir_id() == hir_id =>
+ {
+ Some(parent_def_id.to_def_id())
+ }
+ Node::Variant(Variant { disr_expr: Some(ref constant), .. })
if constant.hir_id == hir_id =>
{
Some(parent_def_id.to_def_id())
let mut visitor = PlaceholderHirTyCollector::default();
visitor.visit_ty(ty);
- let mut diag = bad_placeholder_type(tcx, visitor.0, "return type");
+ let mut diag = bad_placeholder(tcx, "type", visitor.0, "return type");
let ret_ty = fn_sig.skip_binder().output();
if !ret_ty.references_error() {
if !ret_ty.is_closure() {
use rustc_span::{Span, DUMMY_SP};
use super::ItemCtxt;
-use super::{bad_placeholder_type, is_suggestable_infer_ty};
+use super::{bad_placeholder, is_suggestable_infer_ty};
/// Computes the relevant generic parameter for a potential generic const argument.
///
match parent_node {
Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
| Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
- if constant.hir_id == hir_id =>
+ if constant.hir_id() == hir_id =>
{
tcx.types.usize
}
err.emit();
}
None => {
- let mut diag = bad_placeholder_type(tcx, vec![span], kind);
+ let mut diag = bad_placeholder(tcx, "type", vec![span], kind);
if !ty.references_error() {
let mut mk_nameable = MakeNameable::new(tcx);
--- /dev/null
+// To avoid having to `or` gate `_` as an expr.
+#![feature(generic_arg_infer)]
+
+fn foo() -> [u8; _] {
+ //~^ ERROR the const placeholder `_` is not allowed within types on item signatures for generics
+ // FIXME(generic_arg_infer): this error message should say in the return type or sth like that.
+ [0; 3]
+}
+
+fn main() {
+ foo();
+}
--- /dev/null
+error[E0121]: the const placeholder `_` is not allowed within types on item signatures for generics
+ --> $DIR/array-in-sig.rs:4:18
+ |
+LL | fn foo() -> [u8; _] {
+ | ^ not allowed in type signatures
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0121`.
--- /dev/null
+// run-pass
+
+// To avoid having to `or` gate `_` as an expr.
+#![feature(generic_arg_infer)]
+
+fn foo() -> [u8; 3] {
+ let x: [u8; _] = [0; _];
+ x
+}
+
+fn main() {
+ assert_eq!([0; _], foo());
+}
--- /dev/null
+#![feature(generic_arg_infer)]
+
+struct All<'a, T, const N: usize> {
+ v: &'a T,
+}
+
+struct BadInfer<_>;
+//~^ ERROR expected identifier
+//~| ERROR parameter `_` is never used
+
+fn all_fn<'a, T, const N: usize>() {}
+
+fn bad_infer_fn<_>() {}
+//~^ ERROR expected identifier
+
+
+fn main() {
+ let a: All<_, _, _>;
+ all_fn();
+ let v: [u8; _];
+ let v: [u8; 10] = [0; _];
+}
--- /dev/null
+error: expected identifier, found reserved identifier `_`
+ --> $DIR/infer-arg-test.rs:7:17
+ |
+LL | struct BadInfer<_>;
+ | ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+ --> $DIR/infer-arg-test.rs:13:17
+ |
+LL | fn bad_infer_fn<_>() {}
+ | ^ expected identifier, found reserved identifier
+
+error[E0392]: parameter `_` is never used
+ --> $DIR/infer-arg-test.rs:7:17
+ |
+LL | struct BadInfer<_>;
+ | ^ unused parameter
+ |
+ = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `_` to be a const parameter, use `const _: usize` instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
+++ /dev/null
-#![feature(generic_arg_infer)]
-
-struct All<'a, T, const N: usize> {
- v: &'a T,
-}
-
-struct BadInfer<_>;
-//~^ ERROR expected identifier
-//~| ERROR parameter `_` is never used
-
-fn all_fn<'a, T, const N: usize>() {}
-
-fn bad_infer_fn<_>() {}
-//~^ ERROR expected identifier
-
-
-fn main() {
- let a: All<_, _, _>;
- all_fn();
- let v: [u8; _];
- //~^ ERROR in expressions
- let v: [u8; 10] = [0; _];
- //~^ ERROR in expressions
-}
+++ /dev/null
-error: expected identifier, found reserved identifier `_`
- --> $DIR/infer-arg-test.rs:7:17
- |
-LL | struct BadInfer<_>;
- | ^ expected identifier, found reserved identifier
-
-error: expected identifier, found reserved identifier `_`
- --> $DIR/infer-arg-test.rs:13:17
- |
-LL | fn bad_infer_fn<_>() {}
- | ^ expected identifier, found reserved identifier
-
-error: in expressions, `_` can only be used on the left-hand side of an assignment
- --> $DIR/infer-arg-test.rs:20:15
- |
-LL | let v: [u8; _];
- | ^ `_` not allowed here
-
-error: in expressions, `_` can only be used on the left-hand side of an assignment
- --> $DIR/infer-arg-test.rs:22:25
- |
-LL | let v: [u8; 10] = [0; _];
- | ^ `_` not allowed here
-
-error[E0392]: parameter `_` is never used
- --> $DIR/infer-arg-test.rs:7:17
- |
-LL | struct BadInfer<_>;
- | ^ unused parameter
- |
- = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData`
- = help: if you intended `_` to be a const parameter, use `const _: usize` instead
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0392`.