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

Fortify handing of where bounds on trait & trait alias definitions #96715

Merged
merged 4 commits into from
May 10, 2022
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
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 @@ -1070,6 +1070,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 @@ -1333,8 +1334,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 @@ -1368,7 +1370,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]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@compiler-errors Is this not a diagnostics regression?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why would this be a diagnostics regression? i thought the previous error message was nonsense, since trait alias "Alias" has no trait types...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps this is a question for @cjgillot and not me, though?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're right, this isn't a regression. The new error message is somewhat confusing though.

}
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() {}