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

Make associated type bounds in supertrait position implied #112629

Merged
merged 2 commits into from
Jun 29, 2023
Merged
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
62 changes: 27 additions & 35 deletions compiler/rustc_hir_analysis/src/astconv/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ use rustc_span::symbol::Ident;
use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::traits;

use crate::astconv::{AstConv, ConvertedBinding, ConvertedBindingKind};
use crate::astconv::{
AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter,
};
use crate::bounds::Bounds;
use crate::errors::{MultipleRelaxedDefaultBounds, ValueOfAssociatedStructAlreadySpecified};

use super::OnlySelfBounds;

impl<'tcx> dyn AstConv<'tcx> + '_ {
/// Sets `implicitly_sized` to true on `Bounds` if necessary
pub(crate) fn add_implicitly_sized(
Expand Down Expand Up @@ -176,47 +176,39 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
&self,
param_ty: Ty<'tcx>,
ast_bounds: &[hir::GenericBound<'_>],
only_self_bounds: OnlySelfBounds,
filter: PredicateFilter,
) -> Bounds<'tcx> {
let mut bounds = Bounds::default();
self.add_bounds(
param_ty,
ast_bounds.iter(),
&mut bounds,
ty::List::empty(),
only_self_bounds,
);
debug!(?bounds);

bounds
}

/// Convert the bounds in `ast_bounds` that refer to traits which define an associated type
/// named `assoc_name` into ty::Bounds. Ignore the rest.
pub(crate) fn compute_bounds_that_match_assoc_item(
&self,
param_ty: Ty<'tcx>,
ast_bounds: &[hir::GenericBound<'_>],
assoc_name: Ident,
) -> Bounds<'tcx> {
let mut result = Vec::new();

for ast_bound in ast_bounds {
if let Some(trait_ref) = ast_bound.trait_ref()
&& let Some(trait_did) = trait_ref.trait_def_id()
&& self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
{
result.push(ast_bound.clone());
let only_self_bounds = match filter {
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
OnlySelfBounds(false)
}
}
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => OnlySelfBounds(true),
};

let mut bounds = Bounds::default();
self.add_bounds(
param_ty,
result.iter(),
ast_bounds.iter().filter(|bound| {
match filter {
PredicateFilter::All
| PredicateFilter::SelfOnly
| PredicateFilter::SelfAndAssociatedTypeBounds => true,
PredicateFilter::SelfThatDefines(assoc_name) => {
if let Some(trait_ref) = bound.trait_ref()
&& let Some(trait_did) = trait_ref.trait_def_id()
&& self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
{
true
} else {
false
}
}
}
}),
&mut bounds,
ty::List::empty(),
OnlySelfBounds(true),
only_self_bounds,
);
debug!(?bounds);

Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,24 @@ pub struct PathSeg(pub DefId, pub usize);
#[derive(Copy, Clone, Debug)]
pub struct OnlySelfBounds(pub bool);

#[derive(Copy, Clone, Debug)]
pub enum PredicateFilter {
/// All predicates may be implied by the trait.
All,

/// Only traits that reference `Self: ..` are implied by the trait.
SelfOnly,

/// Only traits that reference `Self: ..` and define an associated type
/// with the given ident are implied by the trait.
SelfThatDefines(Ident),

/// Only traits that reference `Self: ..` and their associated type bounds.
/// For example, given `Self: Tr<A: B>`, this would expand to `Self: Tr`
/// and `<Self as Tr>::A: B`.
SelfAndAssociatedTypeBounds,
}

pub trait AstConv<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx>;

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_hir_analysis/src/collect/item_bounds.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::ItemCtxt;
use crate::astconv::{AstConv, OnlySelfBounds};
use crate::astconv::{AstConv, PredicateFilter};
use rustc_hir as hir;
use rustc_infer::traits::util;
use rustc_middle::ty::subst::InternalSubsts;
Expand All @@ -26,7 +26,7 @@ fn associated_type_bounds<'tcx>(
);

let icx = ItemCtxt::new(tcx, assoc_item_def_id);
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false));
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All);
// Associated types are implicitly sized unless a `?Sized` bound is found
icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);

Expand Down Expand Up @@ -68,7 +68,7 @@ fn opaque_type_bounds<'tcx>(
) -> &'tcx [(ty::Clause<'tcx>, Span)] {
ty::print::with_no_queries!({
let icx = ItemCtxt::new(tcx, opaque_def_id);
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false));
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All);
// Opaque types are implicitly sized unless a `?Sized` bound is found
icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
debug!(?bounds);
Expand Down
99 changes: 36 additions & 63 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::astconv::{AstConv, OnlySelfBounds};
use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter};
use crate::bounds::Bounds;
use crate::collect::ItemCtxt;
use crate::constrained_generic_params as cgp;
Expand Down Expand Up @@ -125,7 +125,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
if let Some(self_bounds) = is_trait {
predicates.extend(
icx.astconv()
.compute_bounds(tcx.types.self_param, self_bounds, OnlySelfBounds(false))
.compute_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All)
.clauses(),
);
}
Expand Down Expand Up @@ -530,19 +530,6 @@ pub(super) fn explicit_predicates_of<'tcx>(
}
}

#[derive(Copy, Clone, Debug)]
pub enum PredicateFilter {
/// All predicates may be implied by the trait
All,

/// Only traits that reference `Self: ..` are implied by the trait
SelfOnly,

/// Only traits that reference `Self: ..` and define an associated type
/// with the given ident are implied by the trait
SelfThatDefines(Ident),
}

/// Ensures that the super-predicates of the trait with a `DefId`
/// of `trait_def_id` are converted and stored. This also ensures that
/// the transitive super-predicates are converted.
Expand All @@ -564,11 +551,15 @@ pub(super) fn implied_predicates_of(
tcx: TyCtxt<'_>,
trait_def_id: LocalDefId,
) -> ty::GenericPredicates<'_> {
if tcx.is_trait_alias(trait_def_id.to_def_id()) {
implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::All)
} else {
tcx.super_predicates_of(trait_def_id)
}
implied_predicates_with_filter(
tcx,
trait_def_id.to_def_id(),
if tcx.is_trait_alias(trait_def_id.to_def_id()) {
PredicateFilter::All
} else {
PredicateFilter::SelfAndAssociatedTypeBounds
},
)
}

/// Ensures that the super-predicates of the trait with a `DefId`
Expand Down Expand Up @@ -601,44 +592,14 @@ pub(super) fn implied_predicates_with_filter(
let icx = ItemCtxt::new(tcx, trait_def_id);

let self_param_ty = tcx.types.self_param;
let (superbounds, where_bounds_that_match) = match filter {
PredicateFilter::All => (
// Convert the bounds that follow the colon (or equal in trait aliases)
icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(false)),
// Also include all where clause bounds
icx.type_parameter_bounds_in_generics(
generics,
item.owner_id.def_id,
self_param_ty,
OnlySelfBounds(false),
None,
),
),
PredicateFilter::SelfOnly => (
// Convert the bounds that follow the colon (or equal in trait aliases)
icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(true)),
// Include where clause bounds for `Self`
icx.type_parameter_bounds_in_generics(
generics,
item.owner_id.def_id,
self_param_ty,
OnlySelfBounds(true),
None,
),
),
PredicateFilter::SelfThatDefines(assoc_name) => (
// Convert the bounds that follow the colon (or equal) that reference the associated name
icx.astconv().compute_bounds_that_match_assoc_item(self_param_ty, bounds, assoc_name),
// Include where clause bounds for `Self` that reference the associated name
icx.type_parameter_bounds_in_generics(
generics,
item.owner_id.def_id,
self_param_ty,
OnlySelfBounds(true),
Some(assoc_name),
),
),
};
let superbounds = icx.astconv().compute_bounds(self_param_ty, bounds, filter);

let where_bounds_that_match = icx.type_parameter_bounds_in_generics(
generics,
item.owner_id.def_id,
self_param_ty,
filter,
);

// Combine the two lists to form the complete set of superbounds:
let implied_bounds =
Expand Down Expand Up @@ -743,8 +704,7 @@ pub(super) fn type_param_predicates(
ast_generics,
def_id,
ty,
OnlySelfBounds(true),
Some(assoc_name),
PredicateFilter::SelfThatDefines(assoc_name),
)
.into_iter()
.filter(|(predicate, _)| match predicate.kind().skip_binder() {
Expand All @@ -768,8 +728,7 @@ impl<'tcx> ItemCtxt<'tcx> {
ast_generics: &'tcx hir::Generics<'tcx>,
param_def_id: LocalDefId,
ty: Ty<'tcx>,
only_self_bounds: OnlySelfBounds,
assoc_name: Option<Ident>,
filter: PredicateFilter,
) -> Vec<(ty::Clause<'tcx>, Span)> {
let mut bounds = Bounds::default();

Expand All @@ -778,9 +737,23 @@ impl<'tcx> ItemCtxt<'tcx> {
continue;
};

let (only_self_bounds, assoc_name) = match filter {
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
(OnlySelfBounds(false), None)
}
PredicateFilter::SelfOnly => (OnlySelfBounds(true), None),
PredicateFilter::SelfThatDefines(assoc_name) => {
(OnlySelfBounds(true), Some(assoc_name))
}
};

// Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we
// want to only consider predicates with `Self: ...`, but we don't want
// `OnlySelfBounds(true)` since we want to collect the nested associated
// type bound as well.
let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) {
ty
} else if !only_self_bounds.0 {
} else if matches!(filter, PredicateFilter::All) {
self.to_ty(predicate.bounded_ty)
} else {
continue;
Expand Down
19 changes: 19 additions & 0 deletions tests/ui/associated-type-bounds/implied-in-supertrait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// check-pass

#![feature(associated_type_bounds)]

trait Trait: Super<Assoc: Bound> {}

trait Super {
type Assoc;
}

trait Bound {}

fn foo<T>(x: T)
where
T: Trait,
{
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// edition:2021
// check-pass

#![feature(async_fn_in_trait, return_position_impl_trait_in_trait, return_type_notation)]
//~^ WARN the feature `return_type_notation` is incomplete

use std::future::Future;

struct JoinHandle<T>(fn() -> T);

fn spawn<T>(_: impl Future<Output = T>) -> JoinHandle<T> {
todo!()
}

trait Foo {
async fn bar(&self) -> i32;
}

trait SendFoo: Foo<bar(): Send> + Send {}

fn foobar(foo: impl SendFoo) -> JoinHandle<i32> {
spawn(async move {
let future = foo.bar();
future.await
})
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/rtn-implied-in-supertrait.rs:4:68
|
LL | #![feature(async_fn_in_trait, return_position_impl_trait_in_trait, return_type_notation)]
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
= note: `#[warn(incomplete_features)]` on by default

warning: 1 warning emitted