Skip to content

Commit 43e04fb

Browse files
committed
Auto merge of #58191 - varkor:const-generics-ast, r=petrochenkov
Add const generics to the AST This is mostly split out from #53645 in an effort to make progress merging const generics piecewise instead of in one go. cc @yodaldevoid, @petrochenkov r? @eddyb
2 parents d173180 + f2fe71c commit 43e04fb

File tree

116 files changed

+1085
-709
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+1085
-709
lines changed

src/librustc/hir/def.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ pub enum Def {
5252
AssociatedExistential(DefId),
5353
PrimTy(hir::PrimTy),
5454
TyParam(DefId),
55+
ConstParam(DefId),
5556
SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
5657
ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]`
5758

@@ -265,7 +266,8 @@ impl Def {
265266
Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) |
266267
Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) |
267268
Def::TyAlias(id) | Def::TraitAlias(id) |
268-
Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
269+
Def::AssociatedTy(id) | Def::TyParam(id) | Def::ConstParam(id) | Def::Struct(id) |
270+
Def::StructCtor(id, ..) |
269271
Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
270272
Def::AssociatedConst(id) | Def::Macro(id, ..) |
271273
Def::Existential(id) | Def::AssociatedExistential(id) | Def::ForeignTy(id) => {
@@ -322,6 +324,7 @@ impl Def {
322324
Def::Const(..) => "constant",
323325
Def::AssociatedConst(..) => "associated constant",
324326
Def::TyParam(..) => "type parameter",
327+
Def::ConstParam(..) => "const parameter",
325328
Def::PrimTy(..) => "builtin type",
326329
Def::Local(..) => "local variable",
327330
Def::Upvar(..) => "closure capture",

src/librustc/hir/lowering.rs

+47-32
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,15 @@ impl<'a> LoweringContext<'a> {
11571157
match arg {
11581158
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
11591159
ast::GenericArg::Type(ty) => GenericArg::Type(self.lower_ty_direct(&ty, itctx)),
1160+
ast::GenericArg::Const(ct) => {
1161+
// FIXME(const_generics): const generics are not yet defined in the HIR.
1162+
self.sess.struct_span_err(
1163+
ct.value.span,
1164+
"const generics in any position are currently unsupported",
1165+
).emit();
1166+
self.sess.abort_if_errors();
1167+
bug!();
1168+
}
11601169
}
11611170
}
11621171

@@ -2441,7 +2450,7 @@ impl<'a> LoweringContext<'a> {
24412450
|this| this.lower_param_bounds(&param.bounds, itctx.reborrow()),
24422451
);
24432452

2444-
match param.kind {
2453+
let (name, kind) = match param.kind {
24452454
GenericParamKind::Lifetime => {
24462455
let was_collecting_in_band = self.is_collecting_in_band_lifetimes;
24472456
self.is_collecting_in_band_lifetimes = false;
@@ -2457,22 +2466,14 @@ impl<'a> LoweringContext<'a> {
24572466
| hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()),
24582467
hir::LifetimeName::Error => ParamName::Error,
24592468
};
2460-
let param = hir::GenericParam {
2461-
id: lt.id,
2462-
hir_id: lt.hir_id,
2463-
name: param_name,
2464-
span: lt.span,
2465-
pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
2466-
attrs: self.lower_attrs(&param.attrs),
2467-
bounds,
2468-
kind: hir::GenericParamKind::Lifetime {
2469-
kind: hir::LifetimeParamKind::Explicit,
2470-
}
2469+
2470+
let kind = hir::GenericParamKind::Lifetime {
2471+
kind: hir::LifetimeParamKind::Explicit
24712472
};
24722473

24732474
self.is_collecting_in_band_lifetimes = was_collecting_in_band;
24742475

2475-
param
2476+
(param_name, kind)
24762477
}
24772478
GenericParamKind::Type { ref default, .. } => {
24782479
// Don't expose `Self` (recovered "keyword used as ident" parse error).
@@ -2491,27 +2492,41 @@ impl<'a> LoweringContext<'a> {
24912492
.chain(params)
24922493
.collect();
24932494
}
2494-
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(param.id);
24952495

2496-
hir::GenericParam {
2497-
id: node_id,
2498-
hir_id,
2499-
name: hir::ParamName::Plain(ident),
2500-
pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
2501-
attrs: self.lower_attrs(&param.attrs),
2502-
bounds,
2503-
span: ident.span,
2504-
kind: hir::GenericParamKind::Type {
2505-
default: default.as_ref().map(|x| {
2506-
self.lower_ty(x, ImplTraitContext::disallowed())
2507-
}),
2508-
synthetic: param.attrs.iter()
2509-
.filter(|attr| attr.check_name("rustc_synthetic"))
2510-
.map(|_| hir::SyntheticTyParamKind::ImplTrait)
2511-
.next(),
2512-
}
2513-
}
2496+
let kind = hir::GenericParamKind::Type {
2497+
default: default.as_ref().map(|x| {
2498+
self.lower_ty(x, ImplTraitContext::disallowed())
2499+
}),
2500+
synthetic: param.attrs.iter()
2501+
.filter(|attr| attr.check_name("rustc_synthetic"))
2502+
.map(|_| hir::SyntheticTyParamKind::ImplTrait)
2503+
.next(),
2504+
};
2505+
2506+
(hir::ParamName::Plain(ident), kind)
25142507
}
2508+
GenericParamKind::Const { .. } => {
2509+
// FIXME(const_generics): const generics are not yet defined in the HIR.
2510+
self.sess.struct_span_err(
2511+
param.ident.span,
2512+
"const generics in any position are currently unsupported",
2513+
).emit();
2514+
self.sess.abort_if_errors();
2515+
bug!();
2516+
}
2517+
};
2518+
2519+
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(param.id);
2520+
2521+
hir::GenericParam {
2522+
id: node_id,
2523+
hir_id,
2524+
name,
2525+
span: param.ident.span,
2526+
pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
2527+
attrs: self.lower_attrs(&param.attrs),
2528+
bounds,
2529+
kind,
25152530
}
25162531
}
25172532

src/librustc/hir/map/def_collector.rs

+1
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
218218
let def_path_data = match param.kind {
219219
GenericParamKind::Lifetime { .. } => DefPathData::LifetimeParam(name),
220220
GenericParamKind::Type { .. } => DefPathData::TypeParam(name),
221+
GenericParamKind::Const { .. } => DefPathData::ConstParam(name),
221222
};
222223
self.create_def(param.id, def_path_data, REGULAR_SPACE, param.ident.span);
223224

src/librustc/hir/map/definitions.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -356,10 +356,12 @@ pub enum DefPathData {
356356
/// A closure expression
357357
ClosureExpr,
358358
// Subportions of items
359-
/// A type parameter (generic parameter)
359+
/// A type (generic) parameter
360360
TypeParam(InternedString),
361-
/// A lifetime definition
361+
/// A lifetime (generic) parameter
362362
LifetimeParam(InternedString),
363+
/// A const (generic) parameter
364+
ConstParam(InternedString),
363365
/// A variant of a enum
364366
EnumVariant(InternedString),
365367
/// A struct field
@@ -641,6 +643,7 @@ impl DefPathData {
641643
MacroDef(name) |
642644
TypeParam(name) |
643645
LifetimeParam(name) |
646+
ConstParam(name) |
644647
EnumVariant(name) |
645648
Field(name) |
646649
GlobalMetaData(name) => Some(name),
@@ -669,6 +672,7 @@ impl DefPathData {
669672
MacroDef(name) |
670673
TypeParam(name) |
671674
LifetimeParam(name) |
675+
ConstParam(name) |
672676
EnumVariant(name) |
673677
Field(name) |
674678
GlobalMetaData(name) => {

src/librustc/ich/impls_hir.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,7 @@ impl_stable_hash_for!(enum hir::def::Def {
10461046
AssociatedExistential(def_id),
10471047
PrimTy(prim_ty),
10481048
TyParam(def_id),
1049+
ConstParam(def_id),
10491050
SelfTy(trait_def_id, impl_def_id),
10501051
ForeignTy(def_id),
10511052
Fn(def_id),

src/librustc/ty/item_path.rs

+1
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
325325
data @ DefPathData::Module(..) |
326326
data @ DefPathData::TypeParam(..) |
327327
data @ DefPathData::LifetimeParam(..) |
328+
data @ DefPathData::ConstParam(..) |
328329
data @ DefPathData::EnumVariant(..) |
329330
data @ DefPathData::Field(..) |
330331
data @ DefPathData::AnonConst |

src/librustc/util/ppaux.rs

+1
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ impl PrintContext {
426426
DefPathData::ClosureExpr |
427427
DefPathData::TypeParam(_) |
428428
DefPathData::LifetimeParam(_) |
429+
DefPathData::ConstParam(_) |
429430
DefPathData::Field(_) |
430431
DefPathData::StructCtor |
431432
DefPathData::AnonConst |

src/librustc_passes/ast_validation.rs

+118-16
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
// or type checking or some other kind of complex analysis.
88

99
use std::mem;
10+
use syntax::print::pprust;
1011
use rustc::lint;
1112
use rustc::session::Session;
13+
use rustc_data_structures::fx::FxHashMap;
1214
use syntax::ast::*;
1315
use syntax::attr;
1416
use syntax::source_map::Spanned;
@@ -271,7 +273,74 @@ impl<'a> AstValidator<'a> {
271273
_ => None,
272274
}
273275
}
276+
}
274277

278+
enum GenericPosition {
279+
Param,
280+
Arg,
281+
}
282+
283+
fn validate_generics_order<'a>(
284+
handler: &errors::Handler,
285+
generics: impl Iterator<Item = (ParamKindOrd, Span, Option<String>)>,
286+
pos: GenericPosition,
287+
span: Span,
288+
) {
289+
let mut max_param: Option<ParamKindOrd> = None;
290+
let mut out_of_order = FxHashMap::default();
291+
let mut param_idents = vec![];
292+
293+
for (kind, span, ident) in generics {
294+
if let Some(ident) = ident {
295+
param_idents.push((kind, param_idents.len(), ident));
296+
}
297+
let max_param = &mut max_param;
298+
match max_param {
299+
Some(max_param) if *max_param > kind => {
300+
let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
301+
entry.1.push(span);
302+
}
303+
Some(_) | None => *max_param = Some(kind),
304+
};
305+
}
306+
307+
let mut ordered_params = "<".to_string();
308+
if !out_of_order.is_empty() {
309+
param_idents.sort_by_key(|&(po, i, _)| (po, i));
310+
let mut first = true;
311+
for (_, _, ident) in param_idents {
312+
if !first {
313+
ordered_params += ", ";
314+
}
315+
ordered_params += &ident;
316+
first = false;
317+
}
318+
}
319+
ordered_params += ">";
320+
321+
let pos_str = match pos {
322+
GenericPosition::Param => "parameter",
323+
GenericPosition::Arg => "argument",
324+
};
325+
326+
for (param_ord, (max_param, spans)) in out_of_order {
327+
let mut err = handler.struct_span_err(spans,
328+
&format!(
329+
"{} {pos}s must be declared prior to {} {pos}s",
330+
param_ord,
331+
max_param,
332+
pos = pos_str,
333+
));
334+
if let GenericPosition::Param = pos {
335+
err.span_suggestion(
336+
span,
337+
&format!("reorder the {}s: lifetimes, then types, then consts", pos_str),
338+
ordered_params.clone(),
339+
Applicability::MachineApplicable,
340+
);
341+
}
342+
err.emit();
343+
}
275344
}
276345

277346
impl<'a> Visitor<'a> for AstValidator<'a> {
@@ -412,6 +481,26 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
412481
.note("only trait implementations may be annotated with default").emit();
413482
}
414483
}
484+
ItemKind::Fn(_, header, ref generics, _) => {
485+
// We currently do not permit const generics in `const fn`, as
486+
// this is tantamount to allowing compile-time dependent typing.
487+
if header.constness.node == Constness::Const {
488+
// Look for const generics and error if we find any.
489+
for param in &generics.params {
490+
match param.kind {
491+
GenericParamKind::Const { .. } => {
492+
self.err_handler()
493+
.struct_span_err(
494+
item.span,
495+
"const parameters are not permitted in `const fn`",
496+
)
497+
.emit();
498+
}
499+
_ => {}
500+
}
501+
}
502+
}
503+
}
415504
ItemKind::ForeignMod(..) => {
416505
self.invalid_visibility(
417506
&item.vis,
@@ -508,6 +597,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
508597
match *generic_args {
509598
GenericArgs::AngleBracketed(ref data) => {
510599
walk_list!(self, visit_generic_arg, &data.args);
600+
validate_generics_order(self.err_handler(), data.args.iter().map(|arg| {
601+
(match arg {
602+
GenericArg::Lifetime(..) => ParamKindOrd::Lifetime,
603+
GenericArg::Type(..) => ParamKindOrd::Type,
604+
GenericArg::Const(..) => ParamKindOrd::Const,
605+
}, arg.span(), None)
606+
}), GenericPosition::Arg, generic_args.span());
511607
// Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
512608
// are allowed to contain nested `impl Trait`.
513609
self.with_impl_trait(None, |this| {
@@ -526,34 +622,40 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
526622
}
527623

528624
fn visit_generics(&mut self, generics: &'a Generics) {
529-
let mut seen_non_lifetime_param = false;
530-
let mut seen_default = None;
625+
let mut prev_ty_default = None;
531626
for param in &generics.params {
532-
match (&param.kind, seen_non_lifetime_param) {
533-
(GenericParamKind::Lifetime { .. }, true) => {
627+
if let GenericParamKind::Type { ref default, .. } = param.kind {
628+
if default.is_some() {
629+
prev_ty_default = Some(param.ident.span);
630+
} else if let Some(span) = prev_ty_default {
534631
self.err_handler()
535-
.span_err(param.ident.span, "lifetime parameters must be leading");
536-
},
537-
(GenericParamKind::Lifetime { .. }, false) => {}
538-
(GenericParamKind::Type { ref default, .. }, _) => {
539-
seen_non_lifetime_param = true;
540-
if default.is_some() {
541-
seen_default = Some(param.ident.span);
542-
} else if let Some(span) = seen_default {
543-
self.err_handler()
544-
.span_err(span, "type parameters with a default must be trailing");
545-
break;
546-
}
632+
.span_err(span, "type parameters with a default must be trailing");
633+
break;
547634
}
548635
}
549636
}
637+
638+
validate_generics_order(self.err_handler(), generics.params.iter().map(|param| {
639+
let span = param.ident.span;
640+
let ident = Some(param.ident.to_string());
641+
match &param.kind {
642+
GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, span, ident),
643+
GenericParamKind::Type { .. } => (ParamKindOrd::Type, span, ident),
644+
GenericParamKind::Const { ref ty } => {
645+
let ty = pprust::ty_to_string(ty);
646+
(ParamKindOrd::Const, span, Some(format!("const {}: {}", param.ident, ty)))
647+
}
648+
}
649+
}), GenericPosition::Param, generics.span);
650+
550651
for predicate in &generics.where_clause.predicates {
551652
if let WherePredicate::EqPredicate(ref predicate) = *predicate {
552653
self.err_handler()
553654
.span_err(predicate.span, "equality constraints are not yet \
554655
supported in where clauses (see #20041)");
555656
}
556657
}
658+
557659
visit::walk_generics(self, generics)
558660
}
559661

src/librustc_resolve/diagnostics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -414,8 +414,8 @@ https://doc.rust-lang.org/reference.html#use-declarations
414414
"##,
415415

416416
E0401: r##"
417-
Inner items do not inherit type parameters from the functions they are embedded
418-
in.
417+
Inner items do not inherit type or const parameters from the functions
418+
they are embedded in.
419419
420420
Erroneous code example:
421421

0 commit comments

Comments
 (0)