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

dont provide fwd declared params to cg defaults #86580

Merged
merged 6 commits into from
Jul 24, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1422,6 +1422,9 @@ pub type Lit = Spanned<LitKind>;
/// These are usually found nested inside types (e.g., array lengths)
/// or expressions (e.g., repeat counts), and also used to define
/// explicit discriminant values for enum variants.
///
/// You can check if this anon const is a default in a const param
/// `const N: usize = { ... }` with [Map::opt_const_param_default_param_hir_id]
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
pub struct AnonConst {
pub hir_id: HirId,
Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_middle/src/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,19 @@ impl<'hir> Map<'hir> {
pub fn node_to_string(&self, id: HirId) -> String {
hir_id_to_string(self, id)
}

/// Returns the HirId of `N` in `struct Foo<const N: usize = { ... }>` when
/// called with the HirId for the `{ ... }` anon const
pub fn opt_const_param_default_param_hir_id(&self, anon_const: HirId) -> Option<HirId> {
match self.get(self.get_parent_node(anon_const)) {
Node::GenericParam(GenericParam {
hir_id: param_id,
kind: GenericParamKind::Const { .. },
..
}) => Some(*param_id),
_ => None,
}
}
}

impl<'hir> intravisit::Map<'hir> for Map<'hir> {
Expand Down
32 changes: 31 additions & 1 deletion compiler/rustc_typeck/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1441,6 +1441,25 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
None
} else if tcx.lazy_normalization() {
// Only provide backwards declared generics to cg defaults (#86580)
BoxyUwU marked this conversation as resolved.
Show resolved Hide resolved
if let Some(param_id) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) {
let generics = tcx.generics_of(parent_def_id.to_def_id());
let param_def = tcx.hir().local_def_id(param_id).to_def_id();
let param_def_idx = generics.param_def_id_to_index[&param_def];
let params = generics.params[..param_def_idx as usize].to_owned();
let param_def_id_to_index =
params.iter().map(|param| (param.def_id, param.index)).collect();

return ty::Generics {
parent: generics.parent,
parent_count: generics.parent_count,
params,
param_def_id_to_index,
has_self: generics.has_self,
has_late_bound_regions: generics.has_late_bound_regions,
};
}

// HACK(eddyb) this provides the correct generics when
// `feature(const_generics)` is enabled, so that const expressions
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
Expand Down Expand Up @@ -2359,7 +2378,8 @@ fn trait_explicit_predicates_and_bounds(
}

fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
if let DefKind::Trait = tcx.def_kind(def_id) {
let def_kind = tcx.def_kind(def_id);
if let DefKind::Trait = def_kind {
// Remove bounds on associated types from the predicates, they will be
// returned by `explicit_item_bounds`.
let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
Expand Down Expand Up @@ -2404,6 +2424,16 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
}
}
} else {
if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
// Provide predicates of parent item of cg defaults manually as `generics_of`
BoxyUwU marked this conversation as resolved.
Show resolved Hide resolved
// doesn't set the parent item as the parent for the generics (#86580)
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) {
let item_id = tcx.hir().get_parent_item(hir_id);
let item_def_id = tcx.hir().local_def_id(item_id).to_def_id();
return tcx.explicit_predicates_of(item_def_id);
}
}
gather_explicit_predicates_of(tcx, def_id)
}
}
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_typeck/src/outlives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@ pub fn provide(providers: &mut Providers) {
fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate<'_>, Span)] {
let id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local());

if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization()
{
// Provide predicates of parent item of cg defaults manually as `generics_of`
BoxyUwU marked this conversation as resolved.
Show resolved Hide resolved
// doesn't set the parent item as the parent for the generics (#86580)
if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(id) {
let item_id = tcx.hir().get_parent_item(id);
let item_def_id = tcx.hir().local_def_id(item_id).to_def_id();
return tcx.inferred_outlives_of(item_def_id);
}
}

match tcx.hir().get(id) {
Node::Item(item) => match item.kind {
hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) => {
Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/const-generics/defaults/cec-concrete-default.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#![feature(const_generics, const_evaluatable_checked, const_generics_defaults)]
#![allow(incomplete_features)]

struct Foo<const N: usize, const M: usize = { N + 1 }>;
fn no_constraining() -> Foo<10> {
Foo::<10, 11>
}

pub fn different_than_default() -> Foo<10> {
Foo::<10, 12>
//~^ error: mismatched types
}

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/const-generics/defaults/cec-concrete-default.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0308]: mismatched types
--> $DIR/cec-concrete-default.rs:10:5
|
LL | Foo::<10, 12>
| ^^^^^^^^^^^^^ expected `11_usize`, found `12_usize`
|
= note: expected type `11_usize`
found type `12_usize`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#![feature(const_generics, const_evaluatable_checked, const_generics_defaults)]
#![allow(incomplete_features)]

struct Foo<const N: usize, const M: usize = { N + 1 }>;
fn should_unify<const N: usize>() -> Foo<N> where [(); { N + 1 }]: {
Foo::<N, { N + 1 }>
}
pub fn shouldnt_unify<const N: usize>() -> Foo<N>
where
[(); { N + 1 }]:,
[(); { N + 2 }]:, {
Foo::<N, { N + 2 }>
//~^ error: mismatched types
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0308]: mismatched types
--> $DIR/cec-generic-default-mismatched-types.rs:12:5
|
LL | Foo::<N, { N + 2 }>
| ^^^^^^^^^^^^^^^^^^^ expected `{ N + 1 }`, found `{ N + 2 }`
|
= note: expected type `{ N + 1 }`
found type `{ N + 2 }`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
24 changes: 24 additions & 0 deletions src/test/ui/const-generics/defaults/cec-generic-default.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#![feature(const_evaluatable_checked, const_generics, const_generics_defaults)]
#![allow(incomplete_features)]

pub struct Foo<const N: usize, const M: usize = { N + 1 }>;
pub fn needs_evaluatable_bound<const N1: usize>() -> Foo<N1> {
//~^ error: unconstrained generic constant
loop {}
}
pub fn has_evaluatable_bound<const N1: usize>() -> Foo<N1> where [(); N1 + 1]: {
loop {}
}

type FooAlias<const N: usize, const NP: usize = { N + 1 }> = [(); NP];
fn needs_evaluatable_bound_alias<T, const N: usize>() -> FooAlias<N>
{
//~^^ error: unconstrained generic constant
todo!()
}
fn has_evaluatable_bound_alias<const N: usize>() -> FooAlias<N>
where [(); N + 1]: {
todo!()
}

fn main() {}
18 changes: 18 additions & 0 deletions src/test/ui/const-generics/defaults/cec-generic-default.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error: unconstrained generic constant
--> $DIR/cec-generic-default.rs:5:54
|
LL | pub fn needs_evaluatable_bound<const N1: usize>() -> Foo<N1> {
| ^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); { N + 1 }]:`

error: unconstrained generic constant
--> $DIR/cec-generic-default.rs:14:58
|
LL | fn needs_evaluatable_bound_alias<T, const N: usize>() -> FooAlias<N>
| ^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); { N + 1 }]:`

error: aborting due to 2 previous errors