Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow _ as the length of array types and repeat expressions #91907

Merged
merged 5 commits into from
Jan 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
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)),
Expand Down
23 changes: 22 additions & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ use rustc_hir::{ConstArg, GenericArg, ParamName};
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;
Expand Down Expand Up @@ -1248,7 +1249,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
))
}
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) => {
Expand Down Expand Up @@ -2039,6 +2040,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
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),
Expand Down
18 changes: 16 additions & 2 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1407,6 +1407,20 @@ impl fmt::Display for ConstContext {
/// 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)
Expand Down Expand Up @@ -1756,7 +1770,7 @@ pub enum ExprKind<'hir> {
///
/// 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),
Expand Down Expand Up @@ -2266,7 +2280,7 @@ pub enum TyKind<'hir> {
/// 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`).
Expand Down
14 changes: 12 additions & 2 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,9 @@ pub trait Visitor<'v>: Sized {
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)
}
Expand Down Expand Up @@ -753,7 +756,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
}
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 {
Expand Down Expand Up @@ -1124,6 +1127,13 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
}
}

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);
Expand All @@ -1147,7 +1157,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
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);
Expand Down
13 changes: 10 additions & 3 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ impl<'a> State<'a> {
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) => {
Expand Down Expand Up @@ -1065,6 +1065,13 @@ impl<'a> State<'a> {
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))
}
Expand Down Expand Up @@ -1140,12 +1147,12 @@ impl<'a> State<'a> {
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()
}
Expand Down
9 changes: 6 additions & 3 deletions compiler/rustc_mir_build/src/thir/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -583,9 +583,12 @@ impl<'tcx> Cx<'tcx> {
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 }
}
Expand Down
28 changes: 20 additions & 8 deletions compiler/rustc_save_analysis/src/dump_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1326,12 +1326,18 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
}
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);
Expand Down Expand Up @@ -1390,12 +1396,18 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
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.
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_save_analysis/src/sig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,9 +310,9 @@ impl<'hir> Sig for hir::Ty<'hir> {
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 expr = id_to_string(&scx.tcx.hir(), length.hir_id()).replace('\n', " ");
let text = format!("[{}; {}]", nested_ty.text, expr);
Ok(replace_text(nested_ty, text))
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/astconv/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
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(),
Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_typeck/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2363,8 +2363,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
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)
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_typeck/src/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1238,12 +1238,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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() {
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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);
Expand Down
18 changes: 12 additions & 6 deletions compiler/rustc_typeck/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ crate fn placeholder_type_error<'tcx>(
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 {
Expand Down Expand Up @@ -314,8 +314,9 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
///////////////////////////////////////////////////////////////////////////
// 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> {
Expand All @@ -326,7 +327,8 @@ fn bad_placeholder_type<'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 {
Expand Down Expand Up @@ -393,7 +395,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
_: 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,
Expand Down Expand Up @@ -1482,7 +1484,11 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
// `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())
Expand Down Expand Up @@ -1788,7 +1794,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {

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() {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_typeck/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use rustc_span::symbol::Ident;
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.
///
Expand Down Expand Up @@ -490,7 +490,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
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
}
Expand Down Expand Up @@ -788,7 +788,7 @@ fn infer_placeholder_type<'a>(
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);
Expand Down
Loading