Skip to content

Commit

Permalink
Auto merge of rust-lang#96715 - cjgillot:trait-alias-loop, r=compiler…
Browse files Browse the repository at this point in the history
…-errors

Fortify handing of where bounds on trait & trait alias definitions

Closes rust-lang#96664
Closes rust-lang#96665

Since rust-lang#93803, when listing all bounds and predicates we now need to account for the possible presence of predicates on any of the generic parameters.  Both bugs were hidden by the special handling of bounds at  the generic parameter declaration position.

Trait alias expansion used to confuse predicates on `Self` and where predicates.
Exiting too late when listing all the bounds caused a cycle error.
  • Loading branch information
bors committed May 10, 2022
2 parents cb39073 + e947fad commit 362010d
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 20 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_error_messages/locales/en-US/typeck.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ typeck-copy-impl-on-non-adt =
typeck-trait-object-declared-with-no-traits =
at least one trait is required for an object type
.alias-span = this alias does not contain a trait
typeck-ambiguous-lifetime-bound =
ambiguous lifetime bound, explicit lifetime bound required
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_trait_selection/src/traits/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,14 @@ impl<'tcx> TraitAliasExpander<'tcx> {

// Get components of trait alias.
let predicates = tcx.super_predicates_of(trait_ref.def_id());
debug!(?predicates);

let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
pred.subst_supertrait(tcx, &trait_ref)
.to_opt_poly_trait_pred()
.map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))
});
debug!("expand_trait_aliases: items={:?}", items.clone());
debug!("expand_trait_aliases: items={:?}", items.clone().collect::<Vec<_>>());

self.stack.extend(items);

Expand Down
14 changes: 11 additions & 3 deletions compiler/rustc_typeck/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut bounds = Bounds::default();

self.add_bounds(param_ty, ast_bounds.iter(), &mut bounds, ty::List::empty());
debug!(?bounds);

bounds
}
Expand Down Expand Up @@ -1327,8 +1328,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// is used and no 'maybe' bounds are used.
let expanded_traits =
traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b)));
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
.filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self)
.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
if regular_traits.len() > 1 {
let first_trait = &regular_traits[0];
let additional_trait = &regular_traits[1];
Expand Down Expand Up @@ -1362,7 +1364,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}

if regular_traits.is_empty() && auto_traits.is_empty() {
tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span });
let trait_alias_span = bounds
.trait_bounds
.iter()
.map(|&(trait_ref, _, _)| trait_ref.def_id())
.find(|&trait_ref| tcx.is_trait_alias(trait_ref))
.map(|trait_ref| tcx.def_span(trait_ref));
tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
return tcx.ty_error();
}

Expand Down
13 changes: 8 additions & 5 deletions compiler/rustc_typeck/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ use std::iter;
mod item_bounds;
mod type_of;

#[derive(Debug)]
struct OnlySelfBounds(bool);

///////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -650,6 +651,7 @@ impl<'tcx> ItemCtxt<'tcx> {
/// AST. We do this to avoid having to convert *all* the bounds, which
/// would create artificial cycles. Instead, we can only convert the
/// bounds for a type parameter `X` if `X::Foo` is used.
#[instrument(level = "trace", skip(self, ast_generics))]
fn type_parameter_bounds_in_generics(
&self,
ast_generics: &'tcx hir::Generics<'tcx>,
Expand All @@ -659,6 +661,7 @@ impl<'tcx> ItemCtxt<'tcx> {
assoc_name: Option<Ident>,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
debug!(?param_def_id);
ast_generics
.predicates
.iter()
Expand All @@ -676,13 +679,12 @@ impl<'tcx> ItemCtxt<'tcx> {
};
let bvars = self.tcx.late_bound_vars(bp.bounded_ty.hir_id);

bp.bounds
.iter()
.filter(|b| match assoc_name {
bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b, bvars))).filter(
|(_, b, _)| match assoc_name {
Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
None => true,
})
.filter_map(move |b| bt.map(|bt| (bt, b, bvars)))
},
)
})
.flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
.collect()
Expand Down Expand Up @@ -1140,6 +1142,7 @@ fn super_predicates_that_define_assoc_type(

// Combine the two lists to form the complete set of superbounds:
let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
debug!(?superbounds);

// Now require that immediate supertraits are converted,
// which will, in turn, reach indirect supertraits.
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_typeck/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ pub struct CopyImplOnNonAdt {
pub struct TraitObjectDeclaredWithNoTraits {
#[primary_span]
pub span: Span,
#[label = "alias-span"]
pub trait_alias_span: Option<Span>,
}

#[derive(SessionDiagnostic)]
Expand Down
6 changes: 6 additions & 0 deletions src/test/ui/traits/alias/only-maybe-bound.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
error[E0224]: at least one trait is required for an object type
--> $DIR/only-maybe-bound.rs:13:12
|
LL | trait _1 = _0;
| -------------- this alias does not contain a trait
...
LL | type _T0 = dyn _1;
| ^^^^^^

error[E0224]: at least one trait is required for an object type
--> $DIR/only-maybe-bound.rs:19:12
|
LL | trait _2 = _1 + _1;
| ------------------- this alias does not contain a trait
LL |
LL | type _T1 = dyn _2;
| ^^^^^^

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/traits/issue-65673.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ trait Alias<T> = where T: Trait;

impl<T> WithType for T {
type Ctx = dyn Alias<T>;
//~^ ERROR the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
//~^ ERROR at least one trait is required for an object type [E0224]
}
fn main() {}
16 changes: 6 additions & 10 deletions src/test/ui/traits/issue-65673.stderr
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
error[E0224]: at least one trait is required for an object type
--> $DIR/issue-65673.rs:9:16
|
LL | trait Alias<T> = where T: Trait;
| -------------------------------- this alias does not contain a trait
...
LL | type Ctx = dyn Alias<T>;
| ^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `(dyn Trait + 'static)`
note: required by a bound in `WithType::Ctx`
--> $DIR/issue-65673.rs:4:5
|
LL | type Ctx;
| ^^^^^^^^^ required by this bound in `WithType::Ctx`
| ^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
For more information about this error, try `rustc --explain E0224`.
16 changes: 16 additions & 0 deletions src/test/ui/traits/issue-96664.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// check-pass

#![feature(trait_alias)]

pub trait State = Clone + Send + Sync + PartialOrd + PartialEq + std::fmt::Display;
pub trait RandState<S: State> = FnMut() -> S + Send;

pub trait Evaluator {
type State;
}

pub struct Evolver<E: Evaluator> {
rand_state: Box<dyn RandState<E::State>>,
}

fn main() {}
16 changes: 16 additions & 0 deletions src/test/ui/traits/issue-96665.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// check-pass

pub trait Sequence<Item, Subsequence: Sequence<Item, Subsequence>> {}

pub trait NodeWalk<Graph: GraphBase, NodeSubwalk: NodeWalk<Graph, NodeSubwalk>>:
Sequence<Graph::NodeIndex, NodeSubwalk>
{
}

pub trait GraphBase {
type NodeIndex;
}

pub trait WalkableGraph: GraphBase {}

fn main() {}

0 comments on commit 362010d

Please sign in to comment.