Skip to content

Commit

Permalink
wuwuwuwuwuwu
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Nov 29, 2024
1 parent 0320ee1 commit 22cb94a
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::struct_span_code_err;
use rustc_hir as hir;
Expand Down Expand Up @@ -61,7 +61,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}

let mut trait_bounds = vec![];
let mut projection_bounds = vec![];
let mut projection_bounds = FxIndexMap::default();
for (pred, span) in bounds.clauses() {
let bound_pred = pred.kind();
match bound_pred.skip_binder() {
Expand All @@ -70,7 +70,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_bounds.push((bound_pred.rebind(trait_pred.trait_ref), span));
}
ty::ClauseKind::Projection(proj) => {
projection_bounds.push((bound_pred.rebind(proj), span));
let anon = tcx.anonymize_bound_vars(bound_pred.rebind(proj));
projection_bounds.insert(anon, (bound_pred.rebind(proj), span));
}
ty::ClauseKind::TypeOutlives(_) => {
// Do nothing, we deal with regions separately
Expand All @@ -87,8 +88,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

// Expand trait aliases recursively and check that only one regular (non-auto) trait
// is used and no 'maybe' bounds are used.
let expanded_traits =
traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b)| (a, b)));
let mut trait_alias_projection_bounds = FxIndexSet::default();
let expanded_traits = traits::expand_trait_aliases(
tcx,
&mut trait_alias_projection_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()));
Expand Down Expand Up @@ -162,6 +167,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
let pred = bound_predicate.rebind(pred);

let pred_key = tcx.anonymize_bound_vars(pred);
if !trait_alias_projection_bounds.contains(&pred_key) {
projection_bounds.shift_remove(&pred_key);
}

// A `Self` within the original bound will be instantiated with a
// `trait_object_dummy_self`, so check for that.
let references_self = match pred.skip_binder().term.unpack() {
Expand All @@ -188,8 +199,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See
// the discussion in #56288 for alternatives.
if !references_self {
// Include projections defined on supertraits.
implied_projection_bounds.push(pred);
if trait_alias_projection_bounds.contains(&pred_key) {
// Include projections defined on supertraits.
projection_bounds.insert(pred_key, (pred, supertrait_span));
} else {
// Include projections defined on supertraits.
implied_projection_bounds.push(pred);
}
}

self.check_elaborated_projection_mentions_input_lifetimes(
Expand All @@ -207,7 +223,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated
// types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a
// corresponding `Projection` clause
for (projection_bound, span) in &projection_bounds {
for (projection_bound, span) in projection_bounds.values() {
let def_id = projection_bound.projection_def_id();
let trait_ref = tcx.anonymize_bound_vars(
projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)),
Expand Down Expand Up @@ -314,7 +330,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
})
});

let existential_projections = projection_bounds.iter().map(|(bound, _)| {
let existential_projections = projection_bounds.values().map(|(bound, _)| {
bound.map_bound(|mut b| {
assert_eq!(b.projection_term.self_ty(), dummy_self);

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// For trait aliases, recursively assume all explicitly named traits are relevant
for expansion in traits::expand_trait_aliases(
self.tcx,
&mut Default::default(),
iter::once((ty::Binder::dummy(trait_ref), self.span)),
) {
let bound_trait_ref = expansion.trait_ref();
Expand Down
16 changes: 4 additions & 12 deletions compiler/rustc_middle/src/ty/relate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,12 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
) -> RelateResult<'tcx, Self> {
let tcx = relation.cx();

// FIXME: this is wasteful, but want to do a perf run to see how slow it is.
// We need to perform this deduplication as we sometimes generate duplicate projections
// in `a`.
let mut a_v: Vec<_> = a.into_iter().collect();
let mut b_v: Vec<_> = b.into_iter().collect();
a_v.dedup();
b_v.dedup();
if a_v.len() != b_v.len() {
if a.len() != b.len() {
return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b)));
}

let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| {
match (ep_a.skip_binder(), ep_b.skip_binder()) {
let v =
iter::zip(a, b).map(|(ep_a, ep_b)| match (ep_a.skip_binder(), ep_b.skip_binder()) {
(ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => {
Ok(ep_a.rebind(ty::ExistentialPredicate::Trait(
relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
Expand All @@ -109,8 +102,7 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
ty::ExistentialPredicate::AutoTrait(b),
) if a == b => Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))),
_ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))),
}
});
});
tcx.mk_poly_existential_predicates_from_iter(v)
}
}
Expand Down
39 changes: 24 additions & 15 deletions compiler/rustc_trait_selection/src/traits/util.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::BTreeMap;

use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_errors::Diag;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::InferCtxt;
Expand All @@ -25,9 +25,11 @@ use tracing::debug;
/// `Read + Write + Sync + Send`.
/// Expansion is done via a DFS (depth-first search), and the `visited` field
/// is used to avoid cycles.
pub struct TraitAliasExpander<'tcx> {
pub struct TraitAliasExpander<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
stack: Vec<TraitAliasExpansionInfo<'tcx>>,
// TODO:
projection_bounds: &'a mut FxIndexSet<ty::PolyProjectionPredicate<'tcx>>,
}

/// Stores information about the expansion of a trait via a path of zero or more trait aliases.
Expand Down Expand Up @@ -85,16 +87,17 @@ impl<'tcx> TraitAliasExpansionInfo<'tcx> {
}
}

pub fn expand_trait_aliases<'tcx>(
pub fn expand_trait_aliases<'a, 'tcx>(
tcx: TyCtxt<'tcx>,
projection_bounds: &'a mut FxIndexSet<ty::PolyProjectionPredicate<'tcx>>,
trait_refs: impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)>,
) -> TraitAliasExpander<'tcx> {
) -> TraitAliasExpander<'a, 'tcx> {
let items: Vec<_> =
trait_refs.map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span)).collect();
TraitAliasExpander { tcx, stack: items }
TraitAliasExpander { tcx, stack: items, projection_bounds }
}

impl<'tcx> TraitAliasExpander<'tcx> {
impl<'tcx> TraitAliasExpander<'_, 'tcx> {
/// If `item` is a trait alias and its predicate has not yet been visited, then expands `item`
/// to the definition, pushes the resulting expansion onto `self.stack`, and returns `false`.
/// Otherwise, immediately returns `true` if `item` is a regular trait, or `false` if it is a
Expand Down Expand Up @@ -129,20 +132,26 @@ impl<'tcx> TraitAliasExpander<'tcx> {
let predicates = tcx.explicit_super_predicates_of(trait_ref.def_id());
debug!(?predicates);

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

self.stack.extend(items);
for &(pred, span) in predicates.skip_binder().iter().rev() {
let pred = pred.instantiate_supertrait(tcx, trait_ref);
if let Some(trait_pred) = pred.as_trait_clause() {
// FIXME(negative_bounds): Polarity
self.stack.push(
item.clone_and_push(
trait_pred.map_bound(|trait_pred| trait_pred.trait_ref),
span,
),
);
} else if let Some(proj) = pred.as_projection_clause() {
self.projection_bounds.insert(self.tcx.anonymize_bound_vars(proj));
}
}

false
}
}

impl<'tcx> Iterator for TraitAliasExpander<'tcx> {
impl<'tcx> Iterator for TraitAliasExpander<'_, 'tcx> {
type Item = TraitAliasExpansionInfo<'tcx>;

fn size_hint(&self) -> (usize, Option<usize>) {
Expand Down
4 changes: 1 addition & 3 deletions tests/ui/associated-types/issue-59324.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ pub trait ThriftService<Bug: NotFoo>:
}

fn with_factory<H>(factory: dyn ThriftService<()>) {}
//~^ ERROR the trait bound `(): Foo` is not satisfied
//~| ERROR the trait bound `(): Foo` is not satisfied
//~| ERROR cannot be known at compilation time
//~^ ERROR cannot be known at compilation time

fn main() {}
2 changes: 1 addition & 1 deletion tests/ui/issues/issue-59326.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
//@ check-pass
trait Service {
type S;
}
Expand All @@ -23,4 +22,5 @@ fn make_server<F: Framing>() -> Box<dyn HttpService<F, S = F::F>> {

fn main() {
build_server(|| make_server())
//~^ ERROR mismatched types
}
12 changes: 12 additions & 0 deletions tests/ui/issues/issue-59326.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0308]: mismatched types
--> $DIR/issue-59326.rs:24:21
|
LL | build_server(|| make_server())
| ^^^^^^^^^^^^^ expected trait `HttpService<(), S = ()>`, found trait `HttpService<_>`
|
= note: expected struct `Box<(dyn HttpService<(), S = ()> + 'static)>`
found struct `Box<(dyn HttpService<_> + 'static)>`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0308`.
4 changes: 2 additions & 2 deletions tests/ui/traits/alias/dont-elaborate-non-self.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0277]: the size for values of type `(dyn Fn<()> + 'static)` cannot be known at compilation time
error[E0277]: the size for values of type `(dyn Fn() -> Fut + 'static)` cannot be known at compilation time
--> $DIR/dont-elaborate-non-self.rs:7:14
|
LL | fn f<Fut>(a: dyn F<Fut>) {}
| ^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `(dyn Fn<()> + 'static)`
= help: the trait `Sized` is not implemented for `(dyn Fn() -> Fut + 'static)`
= help: unsized fn params are gated as an unstable feature
help: you can use `impl Trait` as the argument type
|
Expand Down

0 comments on commit 22cb94a

Please sign in to comment.