Auto merge of #96715 - cjgillot:trait-alias-loop, r=compiler-errors
Fortify handing of where bounds on trait & trait alias definitions Closes https://github.com/rust-lang/rust/issues/96664 Closes https://github.com/rust-lang/rust/issues/96665 Since https://github.com/rust-lang/rust/pull/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.
This commit is contained in:
commit
362010d6be
10 changed files with 69 additions and 20 deletions
|
@ -45,6 +45,7 @@ typeck-copy-impl-on-non-adt =
|
||||||
|
|
||||||
typeck-trait-object-declared-with-no-traits =
|
typeck-trait-object-declared-with-no-traits =
|
||||||
at least one trait is required for an object type
|
at least one trait is required for an object type
|
||||||
|
.alias-span = this alias does not contain a trait
|
||||||
|
|
||||||
typeck-ambiguous-lifetime-bound =
|
typeck-ambiguous-lifetime-bound =
|
||||||
ambiguous lifetime bound, explicit lifetime bound required
|
ambiguous lifetime bound, explicit lifetime bound required
|
||||||
|
|
|
@ -118,13 +118,14 @@ impl<'tcx> TraitAliasExpander<'tcx> {
|
||||||
|
|
||||||
// Get components of trait alias.
|
// Get components of trait alias.
|
||||||
let predicates = tcx.super_predicates_of(trait_ref.def_id());
|
let predicates = tcx.super_predicates_of(trait_ref.def_id());
|
||||||
|
debug!(?predicates);
|
||||||
|
|
||||||
let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
|
let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
|
||||||
pred.subst_supertrait(tcx, &trait_ref)
|
pred.subst_supertrait(tcx, &trait_ref)
|
||||||
.to_opt_poly_trait_pred()
|
.to_opt_poly_trait_pred()
|
||||||
.map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))
|
.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);
|
self.stack.extend(items);
|
||||||
|
|
||||||
|
|
|
@ -1064,6 +1064,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
let mut bounds = Bounds::default();
|
let mut bounds = Bounds::default();
|
||||||
|
|
||||||
self.add_bounds(param_ty, ast_bounds.iter(), &mut bounds, ty::List::empty());
|
self.add_bounds(param_ty, ast_bounds.iter(), &mut bounds, ty::List::empty());
|
||||||
|
debug!(?bounds);
|
||||||
|
|
||||||
bounds
|
bounds
|
||||||
}
|
}
|
||||||
|
@ -1327,8 +1328,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
// is used and no 'maybe' bounds are used.
|
// is used and no 'maybe' bounds are used.
|
||||||
let expanded_traits =
|
let expanded_traits =
|
||||||
traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b)));
|
traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b)));
|
||||||
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
|
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
|
||||||
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
|
.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 {
|
if regular_traits.len() > 1 {
|
||||||
let first_trait = ®ular_traits[0];
|
let first_trait = ®ular_traits[0];
|
||||||
let additional_trait = ®ular_traits[1];
|
let additional_trait = ®ular_traits[1];
|
||||||
|
@ -1362,7 +1364,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
}
|
}
|
||||||
|
|
||||||
if regular_traits.is_empty() && auto_traits.is_empty() {
|
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();
|
return tcx.ty_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ use std::iter;
|
||||||
mod item_bounds;
|
mod item_bounds;
|
||||||
mod type_of;
|
mod type_of;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct OnlySelfBounds(bool);
|
struct OnlySelfBounds(bool);
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -650,6 +651,7 @@ impl<'tcx> ItemCtxt<'tcx> {
|
||||||
/// AST. We do this to avoid having to convert *all* the bounds, which
|
/// AST. We do this to avoid having to convert *all* the bounds, which
|
||||||
/// would create artificial cycles. Instead, we can only convert the
|
/// would create artificial cycles. Instead, we can only convert the
|
||||||
/// bounds for a type parameter `X` if `X::Foo` is used.
|
/// bounds for a type parameter `X` if `X::Foo` is used.
|
||||||
|
#[instrument(level = "trace", skip(self, ast_generics))]
|
||||||
fn type_parameter_bounds_in_generics(
|
fn type_parameter_bounds_in_generics(
|
||||||
&self,
|
&self,
|
||||||
ast_generics: &'tcx hir::Generics<'tcx>,
|
ast_generics: &'tcx hir::Generics<'tcx>,
|
||||||
|
@ -659,6 +661,7 @@ impl<'tcx> ItemCtxt<'tcx> {
|
||||||
assoc_name: Option<Ident>,
|
assoc_name: Option<Ident>,
|
||||||
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
||||||
let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
|
let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
|
||||||
|
debug!(?param_def_id);
|
||||||
ast_generics
|
ast_generics
|
||||||
.predicates
|
.predicates
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -676,13 +679,12 @@ impl<'tcx> ItemCtxt<'tcx> {
|
||||||
};
|
};
|
||||||
let bvars = self.tcx.late_bound_vars(bp.bounded_ty.hir_id);
|
let bvars = self.tcx.late_bound_vars(bp.bounded_ty.hir_id);
|
||||||
|
|
||||||
bp.bounds
|
bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b, bvars))).filter(
|
||||||
.iter()
|
|(_, b, _)| match assoc_name {
|
||||||
.filter(|b| match assoc_name {
|
|
||||||
Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
|
Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
|
||||||
None => true,
|
None => true,
|
||||||
})
|
},
|
||||||
.filter_map(move |b| bt.map(|bt| (bt, b, bvars)))
|
)
|
||||||
})
|
})
|
||||||
.flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
|
.flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -1140,6 +1142,7 @@ fn super_predicates_that_define_assoc_type(
|
||||||
|
|
||||||
// Combine the two lists to form the complete set of superbounds:
|
// Combine the two lists to form the complete set of superbounds:
|
||||||
let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
|
let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
|
||||||
|
debug!(?superbounds);
|
||||||
|
|
||||||
// Now require that immediate supertraits are converted,
|
// Now require that immediate supertraits are converted,
|
||||||
// which will, in turn, reach indirect supertraits.
|
// which will, in turn, reach indirect supertraits.
|
||||||
|
|
|
@ -103,6 +103,8 @@ pub struct CopyImplOnNonAdt {
|
||||||
pub struct TraitObjectDeclaredWithNoTraits {
|
pub struct TraitObjectDeclaredWithNoTraits {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
#[label = "alias-span"]
|
||||||
|
pub trait_alias_span: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(SessionDiagnostic)]
|
#[derive(SessionDiagnostic)]
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
error[E0224]: at least one trait is required for an object type
|
error[E0224]: at least one trait is required for an object type
|
||||||
--> $DIR/only-maybe-bound.rs:13:12
|
--> $DIR/only-maybe-bound.rs:13:12
|
||||||
|
|
|
|
||||||
|
LL | trait _1 = _0;
|
||||||
|
| -------------- this alias does not contain a trait
|
||||||
|
...
|
||||||
LL | type _T0 = dyn _1;
|
LL | type _T0 = dyn _1;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error[E0224]: at least one trait is required for an object type
|
error[E0224]: at least one trait is required for an object type
|
||||||
--> $DIR/only-maybe-bound.rs:19:12
|
--> $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;
|
LL | type _T1 = dyn _2;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,6 @@ trait Alias<T> = where T: Trait;
|
||||||
|
|
||||||
impl<T> WithType for T {
|
impl<T> WithType for T {
|
||||||
type Ctx = dyn Alias<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() {}
|
fn main() {}
|
||||||
|
|
|
@ -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
|
--> $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>;
|
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
|
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
src/test/ui/traits/issue-96664.rs
Normal file
16
src/test/ui/traits/issue-96664.rs
Normal file
|
@ -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
src/test/ui/traits/issue-96665.rs
Normal file
16
src/test/ui/traits/issue-96665.rs
Normal file
|
@ -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() {}
|
Loading…
Add table
Add a link
Reference in a new issue