Auto merge of #74676 - lcnr:generics-no-sort, r=varkor

correctly deal with unsorted generic parameters

We now stop sorting generic params and instead correctly handle unsorted params in the rest of the compiler.

We still restrict const params to come after type params though, so this PR does not change anything which
is visible to users.

This might slightly influence perf, so let's prevent any unintentional rollups. @bors rollup=never

r? @varkor
This commit is contained in:
bors 2020-07-24 13:58:36 +00:00
commit cfb6114b2a
5 changed files with 61 additions and 40 deletions

View File

@ -936,20 +936,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
})
});
let mut lowered_params: Vec<_> =
lowered_generics.params.into_iter().chain(in_band_defs).collect();
// FIXME(const_generics): the compiler doesn't always cope with
// unsorted generic parameters at the moment, so we make sure
// that they're ordered correctly here for now. (When we chain
// the `in_band_defs`, we might make the order unsorted.)
lowered_params.sort_by_key(|param| match param.kind {
hir::GenericParamKind::Lifetime { .. } => ParamKindOrd::Lifetime,
hir::GenericParamKind::Type { .. } => ParamKindOrd::Type,
hir::GenericParamKind::Const { .. } => ParamKindOrd::Const,
});
lowered_generics.params = lowered_params.into();
lowered_generics.params.extend(in_band_defs);
let lowered_generics = lowered_generics.into_generics(self.arena);
(lowered_generics, res)

View File

@ -1298,7 +1298,10 @@ fn object_lifetime_defaults_for_item(
}
GenericParamKind::Const { .. } => {
// Generic consts don't impose any constraints.
None
//
// We still store a dummy value here to allow generic parameters
// in an arbitrary order.
Some(Set1::Empty)
}
})
.collect()

View File

@ -1362,13 +1362,9 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
let type_start = own_start - has_self as u32 + params.len() as u32;
let mut i = 0;
// FIXME(const_generics): a few places in the compiler expect generic params
// to be in the order lifetimes, then type params, then const params.
//
// To prevent internal errors in case const parameters are supplied before
// type parameters we first add all type params, then all const params.
params.extend(ast_generics.params.iter().filter_map(|param| {
if let GenericParamKind::Type { ref default, synthetic, .. } = param.kind {
params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => None,
GenericParamKind::Type { ref default, synthetic, .. } => {
if !allow_defaults && default.is_some() {
if !tcx.features().default_type_parameter_fallback {
tcx.struct_span_lint_hir(
@ -1378,7 +1374,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|lint| {
lint.build(
"defaults for type parameters are only allowed in \
`struct`, `enum`, `type`, or `trait` definitions.",
`struct`, `enum`, `type`, or `trait` definitions.",
)
.emit();
},
@ -1403,13 +1399,8 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
};
i += 1;
Some(param_def)
} else {
None
}
}));
params.extend(ast_generics.params.iter().filter_map(|param| {
if let GenericParamKind::Const { .. } = param.kind {
GenericParamKind::Const { .. } => {
let param_def = ty::GenericParamDef {
index: type_start + i as u32,
name: param.name.ident().name,
@ -1419,8 +1410,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
};
i += 1;
Some(param_def)
} else {
None
}
}));
@ -1899,14 +1888,24 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
// Collect the predicates that were written inline by the user on each
// type parameter (e.g., `<T: Foo>`).
for param in ast_generics.params {
if let GenericParamKind::Type { .. } = param.kind {
let name = param.name.ident().name;
let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
index += 1;
match param.kind {
// We already dealt with early bound lifetimes above.
GenericParamKind::Lifetime { .. } => (),
GenericParamKind::Type { .. } => {
let name = param.name.ident().name;
let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
index += 1;
let sized = SizedByDefault::Yes;
let bounds = AstConv::compute_bounds(&icx, param_ty, &param.bounds, sized, param.span);
predicates.extend(bounds.predicates(tcx, param_ty));
let sized = SizedByDefault::Yes;
let bounds =
AstConv::compute_bounds(&icx, param_ty, &param.bounds, sized, param.span);
predicates.extend(bounds.predicates(tcx, param_ty));
}
GenericParamKind::Const { .. } => {
// Bounds on const parameters are currently not possible.
debug_assert!(param.bounds.is_empty());
index += 1;
}
}
}

View File

@ -6,4 +6,14 @@ struct Bad<const N: usize, T> { //~ ERROR type parameters must be declared prior
another: T,
}
fn main() { }
struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
//~^ ERROR type parameters must be declared prior
//~| ERROR lifetime parameters must be declared prior
a: &'a T,
b: &'b U,
}
fn main() {
let _: AlsoBad<7, 'static, u32, 'static, 17, u16>;
//~^ ERROR lifetime provided when a type was expected
}

View File

@ -4,6 +4,18 @@ error: type parameters must be declared prior to const parameters
LL | struct Bad<const N: usize, T> {
| -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
error: lifetime parameters must be declared prior to const parameters
--> $DIR/argument_order.rs:9:32
|
LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
| -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>`
error: type parameters must be declared prior to const parameters
--> $DIR/argument_order.rs:9:36
|
LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
| ---------------------^----------------------^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>`
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/argument_order.rs:1:12
|
@ -13,5 +25,15 @@ LL | #![feature(const_generics)]
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
error: aborting due to previous error; 1 warning emitted
error[E0747]: lifetime provided when a type was expected
--> $DIR/argument_order.rs:17:23
|
LL | let _: AlsoBad<7, 'static, u32, 'static, 17, u16>;
| ^^^^^^^
|
= note: lifetime arguments must be provided before type arguments
= help: reorder the arguments: lifetimes, then types, then consts: `<'a, 'b, T, U, N, M>`
error: aborting due to 4 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0747`.