Skip to content

[WIP] defer adding implicit Sized bounds #86371

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

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
92 changes: 50 additions & 42 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1379,58 +1379,66 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}

// Get the `LocalId` of `bound_pred.bounded_ty`, but only if it's a plain type parameter.
fn get_def_id(&mut self, bound_pred: &WhereBoundPredicate) -> Option<LocalDefId> {
match bound_pred.bounded_ty.kind {
TyKind::Path(None, ref path) => {
if !(path.segments.len() == 1 && bound_pred.bound_generic_params.is_empty()) {
return None;
}
}
_ => return None,
}
if let Some(Res::Def(DefKind::TyParam, def_id)) =
self.resolver.get_partial_res(bound_pred.bounded_ty.id).map(|d| d.base_res())
{
if let Some(def_id) = def_id.as_local() {
return Some(def_id);
}
}
None
}

pub(super) fn lower_generics_mut(
&mut self,
generics: &Generics,
itctx: ImplTraitContext<'_, 'hir>,
) -> GenericsCtor<'hir> {
// Collect `?Trait` bounds in where clause and move them to parameter definitions.
// FIXME: this could probably be done with less rightward drift. It also looks like two
// control paths where `report_error` is called are the only paths that advance to after the
// match statement, so the error reporting could probably just be moved there.
// Collect `?Trait` bounds in where clause and move them to
// parameter definitions. Currently, the decision to add the
// predicate for the implicit `Sized` bound only examines the
// generic parameters, not the where clauses, to discover any
// `?Sized` bounds. (e.g., `AstConv::is_unsized`)
let mut add_bounds: NodeMap<Vec<_>> = Default::default();
for pred in &generics.where_clause.predicates {
if let WherePredicate::BoundPredicate(ref bound_pred) = *pred {
'next_bound: for bound in &bound_pred.bounds {
if let GenericBound::Trait(_, TraitBoundModifier::Maybe) = *bound {
let report_error = |this: &mut Self| {
this.diagnostic().span_err(
bound_pred.bounded_ty.span,
"`?Trait` bounds are only permitted at the \
point where a type parameter is declared",
);
};
// Check if the where clause type is a plain type parameter.
match bound_pred.bounded_ty.kind {
TyKind::Path(None, ref path)
if path.segments.len() == 1
&& bound_pred.bound_generic_params.is_empty() =>
{
if let Some(Res::Def(DefKind::TyParam, def_id)) = self
.resolver
.get_partial_res(bound_pred.bounded_ty.id)
.map(|d| d.base_res())
{
if let Some(def_id) = def_id.as_local() {
for param in &generics.params {
if let GenericParamKind::Type { .. } = param.kind {
if def_id == self.resolver.local_def_id(param.id) {
add_bounds
.entry(param.id)
.or_default()
.push(bound.clone());
continue 'next_bound;
}
}
}
}
}
report_error(self)
}
_ => report_error(self),
let bound_pred = match *pred {
WherePredicate::BoundPredicate(ref bound_pred) => bound_pred,
_ => continue,
};
'next_bound: for bound in &bound_pred.bounds {
if !matches!(*bound, GenericBound::Trait(_, TraitBoundModifier::Maybe)) {
continue;
}
// Check if the where clause type is a plain type parameter.
if let Some(def_id) = self.get_def_id(bound_pred) {
// Search for it in the generic type parameters.
for param in &generics.params {
if !matches!(param.kind, GenericParamKind::Type { .. }) {
continue;
}
if def_id == self.resolver.local_def_id(param.id) {
add_bounds.entry(param.id).or_default().push(bound.clone());
continue 'next_bound;
}
}
}
// Either the `bounded_ty` is not a plain type parameter, or it's not
// found in the generic type parameters list.
self.diagnostic().span_err(
bound_pred.bounded_ty.span,
"`?Trait` bounds are only permitted at the \
point where a type parameter is declared",
);
}
}

Expand Down
22 changes: 16 additions & 6 deletions compiler/rustc_typeck/src/bounds.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Bounds are restrictions applied to some types after they've been converted into the
//! `ty` form from the HIR.

use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::Constness;
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
use rustc_span::Span;
Expand Down Expand Up @@ -53,9 +54,10 @@ impl<'tcx> Bounds<'tcx> {
&self,
tcx: TyCtxt<'tcx>,
param_ty: Ty<'tcx>,
sized_preds_map: Option<&mut FxIndexMap<Ty<'tcx>, (ty::Predicate<'tcx>, Span)>>,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
// If it could be sized, and is, add the `Sized` predicate.
let sized_predicate = self.implicitly_sized.and_then(|span| {
let mut sized_predicate = self.implicitly_sized.and_then(|span| {
tcx.lang_items().sized_trait().map(|sized| {
let trait_ref = ty::Binder::dummy(ty::TraitRef {
def_id: sized,
Expand All @@ -64,17 +66,24 @@ impl<'tcx> Bounds<'tcx> {
(trait_ref.without_const().to_predicate(tcx), span)
})
});

sized_predicate
.into_iter()
.chain(self.region_bounds.iter().map(|&(region_bound, span)| {
// Insert into a map for deferred output of `Sized` predicates, if provided.
if let Some(map) = sized_preds_map {
if let Some(pred) = sized_predicate {
map.insert(param_ty, pred);
// Don't output with the others if it's being deferred.
sized_predicate = None;
}
}
self.region_bounds
.iter()
.map(|&(region_bound, span)| {
(
region_bound
.map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
.to_predicate(tcx),
span,
)
}))
})
.chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
(predicate, span)
Expand All @@ -84,6 +93,7 @@ impl<'tcx> Bounds<'tcx> {
.iter()
.map(|&(projection, span)| (projection.to_predicate(tcx), span)),
)
.chain(sized_predicate.into_iter())
.collect()
}
}
22 changes: 15 additions & 7 deletions compiler/rustc_typeck/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use rustc_ast as ast;
use rustc_ast::{MetaItemKind, NestedMetaItem};
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
Expand Down Expand Up @@ -1127,7 +1127,7 @@ fn super_predicates_that_define_assoc_type(
)
};

let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
let superbounds1 = superbounds1.predicates(tcx, self_param_ty, None);

// Convert any explicit superbounds in the where-clause,
// e.g., `trait Foo where Self: Bar`.
Expand Down Expand Up @@ -2015,6 +2015,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
let generics = tcx.generics_of(def_id);
let parent_count = generics.parent_count as u32;
let has_own_self = generics.has_self && parent_count == 0;
let mut deferred_sized_preds = FxIndexMap::default();

// Below we'll consider the bounds on the type parameters (including `Self`)
// and the explicit where-clauses, but to get the full set of predicates
Expand Down Expand Up @@ -2085,7 +2086,11 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
sized,
param.span,
);
predicates.extend(bounds.predicates(tcx, param_ty));
predicates.extend(bounds.predicates(
tcx,
param_ty,
Some(&mut deferred_sized_preds),
));
}
GenericParamKind::Const { .. } => {
// Bounds on const parameters are currently not possible.
Expand Down Expand Up @@ -2147,7 +2152,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
&mut bounds,
false,
);
predicates.extend(bounds.predicates(tcx, ty));
predicates.extend(bounds.predicates(tcx, ty, None));
}

&hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
Expand All @@ -2161,7 +2166,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
ty,
&mut bounds,
);
predicates.extend(bounds.predicates(tcx, ty));
predicates.extend(bounds.predicates(tcx, ty, None));
}

hir::GenericBound::Outlives(lifetime) => {
Expand Down Expand Up @@ -2208,6 +2213,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
}

// Add the deferred sized predicates.
predicates.extend(deferred_sized_preds.into_iter().map(|(_, v)| v));

let mut predicates: Vec<_> = predicates.into_iter().collect();

// Subtle: before we store the predicates into the tcx, we
Expand Down Expand Up @@ -2403,7 +2411,7 @@ fn predicates_from_bound<'tcx>(
&mut bounds,
false,
);
bounds.predicates(astconv.tcx(), param_ty)
bounds.predicates(astconv.tcx(), param_ty, None)
}
hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
let mut bounds = Bounds::default();
Expand All @@ -2415,7 +2423,7 @@ fn predicates_from_bound<'tcx>(
param_ty,
&mut bounds,
);
bounds.predicates(astconv.tcx(), param_ty)
bounds.predicates(astconv.tcx(), param_ty, None)
}
hir::GenericBound::Outlives(ref lifetime) => {
let region = astconv.ast_region_to_region(lifetime, None);
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_typeck/src/collect/item_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ fn associated_type_bounds<'tcx>(
}
});

let all_bounds = tcx
.arena
.alloc_from_iter(bounds.predicates(tcx, item_ty).into_iter().chain(bounds_from_parent));
let all_bounds = tcx.arena.alloc_from_iter(
bounds.predicates(tcx, item_ty, None).into_iter().chain(bounds_from_parent),
);
debug!("associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id), all_bounds);
all_bounds
}
Expand All @@ -73,7 +73,7 @@ fn opaque_type_bounds<'tcx>(
SizedByDefault::Yes,
span,
)
.predicates(tcx, item_ty);
.predicates(tcx, item_ty, None);

debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ LL | x: Error
::: $SRC_DIR/core/src/hash/mod.rs:LL:COL
|
LL | fn hash<H: Hasher>(&self, state: &mut H);
| - required by this bound in `std::hash::Hash::hash`
| ------ required by this bound in `std::hash::Hash::hash`
|
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/derives/derives-span-Hash-enum.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ LL | Error
::: $SRC_DIR/core/src/hash/mod.rs:LL:COL
|
LL | fn hash<H: Hasher>(&self, state: &mut H);
| - required by this bound in `std::hash::Hash::hash`
| ------ required by this bound in `std::hash::Hash::hash`
|
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/derives/derives-span-Hash-struct.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ LL | x: Error
::: $SRC_DIR/core/src/hash/mod.rs:LL:COL
|
LL | fn hash<H: Hasher>(&self, state: &mut H);
| - required by this bound in `std::hash::Hash::hash`
| ------ required by this bound in `std::hash::Hash::hash`
|
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/derives/derives-span-Hash-tuple-struct.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ LL | Error
::: $SRC_DIR/core/src/hash/mod.rs:LL:COL
|
LL | fn hash<H: Hasher>(&self, state: &mut H);
| - required by this bound in `std::hash::Hash::hash`
| ------ required by this bound in `std::hash::Hash::hash`
|
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)

Expand Down
17 changes: 16 additions & 1 deletion src/test/ui/error-codes/E0275.stderr
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
error[E0275]: overflow evaluating the requirement `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Self>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo`
--> $DIR/E0275.rs:1:1
|
LL | trait Foo {}
| ^^^^^^^^^ required by this bound in `Foo`
|
= help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`E0275`)
note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Self>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
--> $DIR/E0275.rs:5:9
|
LL | impl<T> Foo for T where Bar<T>: Foo {}
| ^^^ ^
= note: 127 redundant requirements hidden
= note: required because of the requirements on the impl of `Foo` for `Self`

error[E0275]: overflow evaluating the requirement `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo`
--> $DIR/E0275.rs:5:33
|
Expand All @@ -16,6 +31,6 @@ LL | impl<T> Foo for T where Bar<T>: Foo {}
= note: 127 redundant requirements hidden
= note: required because of the requirements on the impl of `Foo` for `Bar<T>`

error: aborting due to previous error
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0275`.
17 changes: 13 additions & 4 deletions src/test/ui/error-codes/E0401.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,22 @@ LL | fn helper(sel: &Self) -> u8 {
| use of generic parameter from outer function
| use a type here instead

error[E0282]: type annotations needed
error[E0283]: type annotations needed
--> $DIR/E0401.rs:11:5
|
LL | fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
| ------ required by this bound in `bfnr`
...
LL | bfnr(x);
| ^^^^ cannot infer type for type parameter `U` declared on the function `bfnr`
| ^^^^ cannot infer type for type parameter `V` declared on the function `bfnr`
|
= note: cannot satisfy `_: Baz<_>`
help: consider specifying the type arguments in the function call
|
LL | bfnr::<U, V, W>(x);
| ^^^^^^^^^^^

error: aborting due to 4 previous errors

Some errors have detailed explanations: E0282, E0401.
For more information about an error, try `rustc --explain E0282`.
Some errors have detailed explanations: E0283, E0401.
For more information about an error, try `rustc --explain E0283`.
2 changes: 1 addition & 1 deletion src/test/ui/error-codes/e0119/complex-impl.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ LL | impl<R> External for (Q, R) {}
|
= note: conflicting implementation in crate `complex_impl_support`:
- impl<'a, 'b, 'c, T, U, V, W> External for (T, M<'a, 'b, 'c, Box<U>, V, W>)
where <U as FnOnce<(T,)>>::Output == V, <V as Iterator>::Item == T, 'b: 'a, T: 'a, U: FnOnce<(T,)>, U: 'static, V: Iterator, V: Clone, W: Add, <W as Add>::Output: Copy;
where <U as FnOnce<(T,)>>::Output == V, <V as Iterator>::Item == T, U: FnOnce<(T,)>, 'b: 'a, U: 'static, V: Iterator, T: 'a, V: Clone, W: Add, <W as Add>::Output: Copy;

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/complex-impl.rs:9:1
Expand Down
Loading