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

Add const generics to the AST #58191

Merged
merged 28 commits into from
Feb 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
751dcdf
Add Const kind to AST
varkor Feb 5, 2019
8d83521
Add const_generics feature flag
varkor Feb 5, 2019
0a8d98a
Parse const generics
varkor Feb 5, 2019
d7695ab
Support const generics in derive
varkor Feb 5, 2019
b4ef753
Add pretty-printing for const generics
varkor Feb 5, 2019
ea0d998
Add resolution errors for const generics
varkor Feb 5, 2019
29f7206
Add const params to Def
varkor Feb 5, 2019
2fec52b
Add lowering errors for const generics
varkor Feb 5, 2019
11874a0
Validate generic parameter and argument order in ast_validation
varkor Feb 5, 2019
06abaee
Add error for const parameters depending on type parameters
varkor Feb 5, 2019
3991ba7
Support const generics in save analysis
varkor Feb 5, 2019
8fd5979
Add const generics feature gate test
varkor Feb 5, 2019
455d659
Update tests
varkor Feb 5, 2019
2f73245
Add test forbidding const parameters in const fn
varkor Feb 5, 2019
ed51b61
Add test for const parameter depending on type parameter
varkor Feb 5, 2019
bf2f62c
Add test for const parameter before other generic parameters
varkor Feb 5, 2019
1805546
Fix const generic parameter save analysis
varkor Feb 5, 2019
7461a5e
Fix ast_validation printing of const generics
varkor Feb 5, 2019
899d013
Fix E0670 doc error
varkor Feb 5, 2019
bbdcc4e
Adjust parser generic parameter errors
varkor Feb 7, 2019
61f35f0
Adjust generic const param resolution
varkor Feb 7, 2019
b3015ab
Fix update to 2018 edition
varkor Feb 7, 2019
dbc7924
Add test for generic parameter list solely containing an attribute
varkor Feb 7, 2019
9ad04b9
Add warning for a parameter list with an attribute but no parameters
varkor Feb 7, 2019
451f128
Parse negative literals in const generic arguments
varkor Feb 7, 2019
4e0e188
Make name resolution handle consts in GenericParamsFromOuterFunction …
varkor Feb 7, 2019
1b933a5
Add a test forbidding the use of const parameters in inner items
varkor Feb 7, 2019
f2fe71c
Resolve incorrect diagnostic for using a non-const value in a constant
varkor Feb 7, 2019
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
5 changes: 4 additions & 1 deletion src/librustc/hir/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pub enum Def {
AssociatedExistential(DefId),
PrimTy(hir::PrimTy),
TyParam(DefId),
ConstParam(DefId),
SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]`

Expand Down Expand Up @@ -265,7 +266,8 @@ impl Def {
Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) |
Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) |
Def::TyAlias(id) | Def::TraitAlias(id) |
Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
Def::AssociatedTy(id) | Def::TyParam(id) | Def::ConstParam(id) | Def::Struct(id) |
Def::StructCtor(id, ..) |
Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
Def::AssociatedConst(id) | Def::Macro(id, ..) |
Def::Existential(id) | Def::AssociatedExistential(id) | Def::ForeignTy(id) => {
Expand Down Expand Up @@ -322,6 +324,7 @@ impl Def {
Def::Const(..) => "constant",
Def::AssociatedConst(..) => "associated constant",
Def::TyParam(..) => "type parameter",
Def::ConstParam(..) => "const parameter",
Def::PrimTy(..) => "builtin type",
Def::Local(..) => "local variable",
Def::Upvar(..) => "closure capture",
Expand Down
79 changes: 47 additions & 32 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,15 @@ impl<'a> LoweringContext<'a> {
match arg {
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
ast::GenericArg::Type(ty) => GenericArg::Type(self.lower_ty_direct(&ty, itctx)),
ast::GenericArg::Const(ct) => {
// FIXME(const_generics): const generics are not yet defined in the HIR.
self.sess.struct_span_err(
ct.value.span,
"const generics in any position are currently unsupported",
).emit();
self.sess.abort_if_errors();
bug!();
}
}
}

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

match param.kind {
let (name, kind) = match param.kind {
GenericParamKind::Lifetime => {
let was_collecting_in_band = self.is_collecting_in_band_lifetimes;
self.is_collecting_in_band_lifetimes = false;
Expand All @@ -2457,22 +2466,14 @@ impl<'a> LoweringContext<'a> {
| hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()),
hir::LifetimeName::Error => ParamName::Error,
};
let param = hir::GenericParam {
id: lt.id,
hir_id: lt.hir_id,
name: param_name,
span: lt.span,
pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
attrs: self.lower_attrs(&param.attrs),
bounds,
kind: hir::GenericParamKind::Lifetime {
kind: hir::LifetimeParamKind::Explicit,
}

let kind = hir::GenericParamKind::Lifetime {
kind: hir::LifetimeParamKind::Explicit
};

self.is_collecting_in_band_lifetimes = was_collecting_in_band;

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

hir::GenericParam {
id: node_id,
hir_id,
name: hir::ParamName::Plain(ident),
pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
attrs: self.lower_attrs(&param.attrs),
bounds,
span: ident.span,
kind: hir::GenericParamKind::Type {
default: default.as_ref().map(|x| {
self.lower_ty(x, ImplTraitContext::disallowed())
}),
synthetic: param.attrs.iter()
.filter(|attr| attr.check_name("rustc_synthetic"))
.map(|_| hir::SyntheticTyParamKind::ImplTrait)
.next(),
}
}
let kind = hir::GenericParamKind::Type {
default: default.as_ref().map(|x| {
self.lower_ty(x, ImplTraitContext::disallowed())
}),
synthetic: param.attrs.iter()
.filter(|attr| attr.check_name("rustc_synthetic"))
.map(|_| hir::SyntheticTyParamKind::ImplTrait)
.next(),
};

(hir::ParamName::Plain(ident), kind)
}
GenericParamKind::Const { .. } => {
// FIXME(const_generics): const generics are not yet defined in the HIR.
self.sess.struct_span_err(
param.ident.span,
"const generics in any position are currently unsupported",
).emit();
self.sess.abort_if_errors();
bug!();
}
};

let LoweredNodeId { node_id, hir_id } = self.lower_node_id(param.id);

hir::GenericParam {
id: node_id,
hir_id,
name,
span: param.ident.span,
pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
attrs: self.lower_attrs(&param.attrs),
bounds,
kind,
}
}

Expand Down
1 change: 1 addition & 0 deletions src/librustc/hir/map/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
let def_path_data = match param.kind {
GenericParamKind::Lifetime { .. } => DefPathData::LifetimeParam(name),
GenericParamKind::Type { .. } => DefPathData::TypeParam(name),
GenericParamKind::Const { .. } => DefPathData::ConstParam(name),
};
self.create_def(param.id, def_path_data, REGULAR_SPACE, param.ident.span);

Expand Down
8 changes: 6 additions & 2 deletions src/librustc/hir/map/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,10 +356,12 @@ pub enum DefPathData {
/// A closure expression
ClosureExpr,
// Subportions of items
/// A type parameter (generic parameter)
/// A type (generic) parameter
TypeParam(InternedString),
/// A lifetime definition
/// A lifetime (generic) parameter
LifetimeParam(InternedString),
/// A const (generic) parameter
ConstParam(InternedString),
/// A variant of a enum
EnumVariant(InternedString),
/// A struct field
Expand Down Expand Up @@ -641,6 +643,7 @@ impl DefPathData {
MacroDef(name) |
TypeParam(name) |
LifetimeParam(name) |
ConstParam(name) |
EnumVariant(name) |
Field(name) |
GlobalMetaData(name) => Some(name),
Expand Down Expand Up @@ -669,6 +672,7 @@ impl DefPathData {
MacroDef(name) |
TypeParam(name) |
LifetimeParam(name) |
ConstParam(name) |
EnumVariant(name) |
Field(name) |
GlobalMetaData(name) => {
Expand Down
1 change: 1 addition & 0 deletions src/librustc/ich/impls_hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,7 @@ impl_stable_hash_for!(enum hir::def::Def {
AssociatedExistential(def_id),
PrimTy(prim_ty),
TyParam(def_id),
ConstParam(def_id),
SelfTy(trait_def_id, impl_def_id),
ForeignTy(def_id),
Fn(def_id),
Expand Down
1 change: 1 addition & 0 deletions src/librustc/ty/item_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
data @ DefPathData::Module(..) |
data @ DefPathData::TypeParam(..) |
data @ DefPathData::LifetimeParam(..) |
data @ DefPathData::ConstParam(..) |
data @ DefPathData::EnumVariant(..) |
data @ DefPathData::Field(..) |
data @ DefPathData::AnonConst |
Expand Down
1 change: 1 addition & 0 deletions src/librustc/util/ppaux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ impl PrintContext {
DefPathData::ClosureExpr |
DefPathData::TypeParam(_) |
DefPathData::LifetimeParam(_) |
DefPathData::ConstParam(_) |
DefPathData::Field(_) |
DefPathData::StructCtor |
DefPathData::AnonConst |
Expand Down
134 changes: 118 additions & 16 deletions src/librustc_passes/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
// or type checking or some other kind of complex analysis.

use std::mem;
use syntax::print::pprust;
use rustc::lint;
use rustc::session::Session;
use rustc_data_structures::fx::FxHashMap;
use syntax::ast::*;
use syntax::attr;
use syntax::source_map::Spanned;
Expand Down Expand Up @@ -271,7 +273,74 @@ impl<'a> AstValidator<'a> {
_ => None,
}
}
}

enum GenericPosition {
Param,
Arg,
}

fn validate_generics_order<'a>(
handler: &errors::Handler,
generics: impl Iterator<Item = (ParamKindOrd, Span, Option<String>)>,
pos: GenericPosition,
span: Span,
) {
let mut max_param: Option<ParamKindOrd> = None;
let mut out_of_order = FxHashMap::default();
let mut param_idents = vec![];

for (kind, span, ident) in generics {
if let Some(ident) = ident {
param_idents.push((kind, param_idents.len(), ident));
}
let max_param = &mut max_param;
match max_param {
Some(max_param) if *max_param > kind => {
let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
entry.1.push(span);
}
Some(_) | None => *max_param = Some(kind),
};
}

let mut ordered_params = "<".to_string();
if !out_of_order.is_empty() {
param_idents.sort_by_key(|&(po, i, _)| (po, i));
let mut first = true;
for (_, _, ident) in param_idents {
if !first {
ordered_params += ", ";
}
ordered_params += &ident;
first = false;
}
}
ordered_params += ">";

let pos_str = match pos {
GenericPosition::Param => "parameter",
GenericPosition::Arg => "argument",
};

for (param_ord, (max_param, spans)) in out_of_order {
let mut err = handler.struct_span_err(spans,
&format!(
"{} {pos}s must be declared prior to {} {pos}s",
param_ord,
max_param,
pos = pos_str,
));
if let GenericPosition::Param = pos {
err.span_suggestion(
span,
&format!("reorder the {}s: lifetimes, then types, then consts", pos_str),
ordered_params.clone(),
Applicability::MachineApplicable,
);
}
err.emit();
}
}

impl<'a> Visitor<'a> for AstValidator<'a> {
Expand Down Expand Up @@ -412,6 +481,26 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
.note("only trait implementations may be annotated with default").emit();
}
}
ItemKind::Fn(_, header, ref generics, _) => {
// We currently do not permit const generics in `const fn`, as
// this is tantamount to allowing compile-time dependent typing.
if header.constness.node == Constness::Const {
// Look for const generics and error if we find any.
for param in &generics.params {
match param.kind {
GenericParamKind::Const { .. } => {
self.err_handler()
.struct_span_err(
item.span,
"const parameters are not permitted in `const fn`",
)
.emit();
}
_ => {}
}
}
}
}
ItemKind::ForeignMod(..) => {
self.invalid_visibility(
&item.vis,
Expand Down Expand Up @@ -508,6 +597,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
match *generic_args {
GenericArgs::AngleBracketed(ref data) => {
walk_list!(self, visit_generic_arg, &data.args);
validate_generics_order(self.err_handler(), data.args.iter().map(|arg| {
(match arg {
GenericArg::Lifetime(..) => ParamKindOrd::Lifetime,
GenericArg::Type(..) => ParamKindOrd::Type,
GenericArg::Const(..) => ParamKindOrd::Const,
}, arg.span(), None)
}), GenericPosition::Arg, generic_args.span());
// Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
// are allowed to contain nested `impl Trait`.
self.with_impl_trait(None, |this| {
Expand All @@ -526,34 +622,40 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}

fn visit_generics(&mut self, generics: &'a Generics) {
let mut seen_non_lifetime_param = false;
let mut seen_default = None;
let mut prev_ty_default = None;
for param in &generics.params {
match (&param.kind, seen_non_lifetime_param) {
(GenericParamKind::Lifetime { .. }, true) => {
if let GenericParamKind::Type { ref default, .. } = param.kind {
if default.is_some() {
prev_ty_default = Some(param.ident.span);
} else if let Some(span) = prev_ty_default {
self.err_handler()
.span_err(param.ident.span, "lifetime parameters must be leading");
},
(GenericParamKind::Lifetime { .. }, false) => {}
(GenericParamKind::Type { ref default, .. }, _) => {
seen_non_lifetime_param = true;
if default.is_some() {
seen_default = Some(param.ident.span);
} else if let Some(span) = seen_default {
self.err_handler()
.span_err(span, "type parameters with a default must be trailing");
break;
}
.span_err(span, "type parameters with a default must be trailing");
break;
}
}
}

validate_generics_order(self.err_handler(), generics.params.iter().map(|param| {
let span = param.ident.span;
let ident = Some(param.ident.to_string());
match &param.kind {
GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, span, ident),
GenericParamKind::Type { .. } => (ParamKindOrd::Type, span, ident),
GenericParamKind::Const { ref ty } => {
let ty = pprust::ty_to_string(ty);
(ParamKindOrd::Const, span, Some(format!("const {}: {}", param.ident, ty)))
}
}
}), GenericPosition::Param, generics.span);

for predicate in &generics.where_clause.predicates {
if let WherePredicate::EqPredicate(ref predicate) = *predicate {
self.err_handler()
.span_err(predicate.span, "equality constraints are not yet \
supported in where clauses (see #20041)");
}
}

visit::walk_generics(self, generics)
}

Expand Down
4 changes: 2 additions & 2 deletions src/librustc_resolve/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,8 @@ https://doc.rust-lang.org/reference.html#use-declarations
"##,

E0401: r##"
Inner items do not inherit type parameters from the functions they are embedded
in.
Inner items do not inherit type or const parameters from the functions
they are embedded in.

Erroneous code example:

Expand Down
Loading