Skip to content

Commit eaa393c

Browse files
committed
Enforce ordering for const generic parameters
1 parent f04dd04 commit eaa393c

File tree

6 files changed

+71
-39
lines changed

6 files changed

+71
-39
lines changed

src/librustc/ty/relate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
476476
}
477477
match x.val {
478478
ConstValue::Unevaluated(def_id, substs) => {
479-
// TODO(varkor): this case should be entirely removed.
479+
// TODO(const_generics): this case should be entirely removed.
480480
// FIXME(eddyb) get the right param_env.
481481
let param_env = ty::ParamEnv::empty();
482482
match tcx.lift_to_global(&substs) {

src/librustc_passes/ast_validation.rs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -429,30 +429,32 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
429429
}
430430

431431
fn visit_generics(&mut self, generics: &'a Generics) {
432-
let mut seen_non_lifetime_param = false;
433-
let mut seen_default = None;
432+
let mut max_param: Option<ParamKindOrd> = None;
433+
let mut prev_ty_default = None;
434434
for param in &generics.params {
435-
match (&param.kind, seen_non_lifetime_param) {
436-
(GenericParamKind::Lifetime { .. }, true) => {
437-
self.err_handler()
438-
.span_err(param.ident.span, "lifetime parameters must be leading");
439-
},
440-
(GenericParamKind::Lifetime { .. }, false) => {}
441-
(GenericParamKind::Type { ref default, .. }, _) => {
442-
seen_non_lifetime_param = true;
435+
let param_ord = match param.kind {
436+
GenericParamKind::Lifetime { .. } => ParamKindOrd::Lifetime,
437+
GenericParamKind::Type { ref default, .. } => {
443438
if default.is_some() {
444-
seen_default = Some(param.ident.span);
445-
} else if let Some(span) = seen_default {
439+
prev_ty_default = Some(param.ident.span);
440+
} else if let Some(span) = prev_ty_default {
446441
self.err_handler()
447442
.span_err(span, "type parameters with a default must be trailing");
448443
break;
449444
}
445+
ParamKindOrd::Type
450446
}
451-
(GenericParamKind::Const { .. }, _) => {
452-
seen_non_lifetime_param = true;
453-
// TODO(const_generics): defaults
447+
GenericParamKind::Const { .. } => ParamKindOrd::Const,
448+
};
449+
let max_param = &mut max_param;
450+
match max_param {
451+
Some(max_param) if *max_param > param_ord => {
452+
self.err_handler().span_err(param.ident.span,
453+
&format!("{} parameters must be placed before {} parameters",
454+
param_ord, max_param));
454455
}
455-
}
456+
Some(_) | None => *max_param = Some(param_ord),
457+
};
456458
}
457459
for predicate in &generics.where_clause.predicates {
458460
if let WherePredicate::EqPredicate(ref predicate) = *predicate {

src/librustdoc/clean/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3120,7 +3120,7 @@ impl Clean<Path> for hir::Path {
31203120
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
31213121
pub enum GenericArgs {
31223122
AngleBracketed {
3123-
// TODO(varkor): clean this up
3123+
// TODO(const_generics): clean this up
31243124
lifetimes: Vec<Lifetime>,
31253125
types: Vec<Type>,
31263126
consts: Vec<Constant>,

src/librustdoc/html/format.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ impl fmt::Display for clean::GenericArgs {
315315
ref consts,
316316
ref bindings,
317317
} => {
318-
// TODO(varkor): clean this up
318+
// TODO(const_generics): clean this up
319319
if !lifetimes.is_empty() ||
320320
!types.is_empty() ||
321321
!consts.is_empty() ||

src/libsyntax/ast.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,26 @@ impl GenericBound {
299299

300300
pub type GenericBounds = Vec<GenericBound>;
301301

302+
/// Specifies the enforced ordering for generic parameters. In the future,
303+
/// if we wanted to relax this order, we could override `PartialEq`/`PartialOrd`,
304+
/// to allow the kinds to be equal.
305+
#[derive(PartialEq, PartialOrd)]
306+
pub enum ParamKindOrd {
307+
Lifetime,
308+
Type,
309+
Const,
310+
}
311+
312+
impl fmt::Display for ParamKindOrd {
313+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
314+
match self {
315+
ParamKindOrd::Lifetime => "lifetime".fmt(f),
316+
ParamKindOrd::Type => "type".fmt(f),
317+
ParamKindOrd::Const => "const".fmt(f),
318+
}
319+
}
320+
}
321+
302322
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
303323
pub enum GenericParamKind {
304324
/// A lifetime definition, e.g. `'a: 'b+'c+'d`.
@@ -1412,7 +1432,7 @@ impl fmt::Debug for ConstTy {
14121432

14131433
impl fmt::Display for ConstTy {
14141434
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1415-
write!(f, "{:?}", self) // TODO(varkor)
1435+
write!(f, "{:?}", self) // TODO(const_generics)
14161436
}
14171437
}
14181438

src/libsyntax/parse/parser.rs

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ use ast::{Visibility, VisibilityKind, WhereClause, CrateSugar};
4141
use ast::{UseTree, UseTreeKind};
4242
use ast::{BinOpKind, UnOp};
4343
use ast::{RangeEnd, RangeSyntax};
44+
use ast::ParamKindOrd;
4445
use {ast, attr};
4546
use source_map::{self, SourceMap, Spanned, respan};
4647
use syntax_pos::{self, Span, MultiSpan, BytePos, FileName, edition::Edition};
@@ -5064,17 +5065,29 @@ impl<'a> Parser<'a> {
50645065
/// Parses (possibly empty) list of lifetime, const, and type parameters, possibly including
50655066
/// trailing comma and erroneous trailing attributes.
50665067
crate fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericParam>> {
5067-
let mut params = Vec::new();
5068-
let mut seen_non_lifetime_param = false;
5068+
let mut params = vec![];
5069+
let mut max_param = None;
5070+
fn enforce_param_order(parser: &Parser,
5071+
max_param: &mut Option<ParamKindOrd>,
5072+
param_ord: ParamKindOrd) {
5073+
match max_param {
5074+
Some(max_param) if *max_param > param_ord => {
5075+
parser.span_err(parser.prev_span,
5076+
&format!("{} parameters must be declared prior to {} parameters",
5077+
param_ord, max_param));
5078+
}
5079+
Some(_) | None => *max_param = Some(param_ord),
5080+
}
5081+
}
50695082
loop {
50705083
let attrs = self.parse_outer_attributes()?;
50715084
if self.check_lifetime() {
5072-
let lifetime = self.expect_lifetime();
50735085
// Parse lifetime parameter.
5086+
let lifetime = self.expect_lifetime();
50745087
let bounds = if self.eat(&token::Colon) {
50755088
self.parse_lt_param_bounds()
50765089
} else {
5077-
Vec::new()
5090+
vec![]
50785091
};
50795092
params.push(ast::GenericParam {
50805093
ident: lifetime.ident,
@@ -5083,28 +5096,25 @@ impl<'a> Parser<'a> {
50835096
bounds,
50845097
kind: ast::GenericParamKind::Lifetime,
50855098
});
5086-
if seen_non_lifetime_param {
5087-
self.span_err(self.prev_span,
5088-
"lifetime parameters must be declared prior to type and const parameters");
5089-
}
5090-
} else if self.check_const_param() {
5091-
// TODO(const_generics): should const parameters be forced to be after type parameters?
5092-
params.push(self.parse_const_param(attrs)?);
5093-
seen_non_lifetime_param = true;
5099+
enforce_param_order(&self, &mut max_param, ParamKindOrd::Lifetime);
50945100
} else if self.check_ident() {
50955101
// Parse type parameter.
50965102
params.push(self.parse_ty_param(attrs)?);
5097-
seen_non_lifetime_param = true;
5103+
enforce_param_order(&self, &mut max_param, ParamKindOrd::Type);
5104+
} else if self.check_const_param() {
5105+
// Parse const parameter.
5106+
params.push(self.parse_const_param(attrs)?);
5107+
enforce_param_order(&self, &mut max_param, ParamKindOrd::Const);
50985108
} else {
50995109
// Check for trailing attributes and stop parsing.
51005110
if !attrs.is_empty() {
5101-
let param_kind = if seen_non_lifetime_param {
5102-
"type and const"
5111+
if let Some(max_param) = max_param {
5112+
self.span_err(attrs[0].span,
5113+
&format!("trailing attribute after {} parameters", max_param));
51035114
} else {
5104-
"lifetime"
5105-
};
5106-
self.span_err(attrs[0].span,
5107-
&format!("trailing attribute after {} parameters", param_kind));
5115+
self.span_err(attrs[0].span,
5116+
"leading attribute before generic parameters");
5117+
}
51085118
}
51095119
break
51105120
}

0 commit comments

Comments
 (0)