Rollup merge of #136458 - compiler-errors:fix-3, r=lcnr
Do not deduplicate list of associated types provided by dyn principal ## Background The way that we handle a dyn trait type's projection bounds is very *structural* today. A dyn trait is represented as a list of `PolyExistentialPredicate`s, which in most cases will be a principal trait (like `Iterator`) and a list of projections (like `Item = u32`). Importantly, the list of projections comes from user-written associated type bounds on the type *and* from elaborating the projections from the principal's supertraits. For example, given a set of traits like: ```rust trait Foo<T> { type Assoc; } trait Bar<A, B>: Foo<A, Assoc = A> + Foo<B, Assoc = B> {} ``` For the type `dyn Bar<i32, u32>`, the list of projections will be something like `[Foo<i32>::Assoc = i32, Foo<u32>::Assoc = u32]`. We deduplicate these projections when they're identical, so for `dyn Bar<(), ()>` would be something like `[Foo<()>::Assoc = ()]`. ## Shortcomings 1: inference We face problems when we begin to mix this structural notion of projection bounds with inference and associated type normalization. For example, let's try calling a generic function that takes `dyn Bar<A, B>` with a value of type `dyn Bar<(), ()>`: ```rust trait Foo<T> { type Assoc; } trait Bar<A, B>: Foo<A, Assoc = A> + Foo<B, Assoc = B> {} fn call_bar<A, B>(_: &dyn Bar<A, B>) {} fn test(x: &dyn Bar<(), ()>) { call_bar(x); // ^ ERROR mismatched types } ``` ``` error[E0308]: mismatched types --> /home/mgx/test.rs:10:14 | 10 | call_bar(x); | -------- ^ expected trait `Bar<_, _>`, found trait `Bar<(), ()>` ``` What's going on here? Well, when calling `call_bar`, the generic signature `&dyn Bar<?A, ?B>` does not unify with `&dyn Bar<(), ()>` because the list of projections differ -- `[Foo<?A>::Assoc = ?A, Foo<?B>::Assoc = ?B]` vs `[Foo<()>::Assoc = ()]`. A simple solution to this may be to unify the principal traits first, then attempt to deduplicate them after inference. In this case, if we constrain `?A = ?B = ()`, then we would be able to deduplicate those projections in the first list. However, this idea is still pretty fragile, and it's not a complete solution. ## Shortcomings 2: normalization Consider a slightly modified example: ```rust //@ compile-flags: -Znext-solver trait Mirror { type Assoc; } impl<T> Mirror for T { type Assoc = T; } fn call_bar(_: &dyn Bar<(), <() as Mirror>::Assoc>) {} fn test(x: &dyn Bar<(), ()>) { call_bar(x); } ``` This fails in the new solver. In this example, we try to unify `dyn Bar<(), ()>` and `dyn Bar<(), <() as Mirror>::Assoc>`. We are faced with the same problem even though there are no inference variables, and making this work relies on eagerly and deeply normalizing all projections so that they can be structurally deduplicated. This is incompatible with how we handle associated types in the new trait solver, and while we could perhaps support it with some major gymnastics in the new solver, it suggests more fundamental shortcomings with how we deal with projection bounds in the new solver. ## Shortcomings 3: redundant projections Consider a final example: ```rust trait Foo { type Assoc; } trait Bar: Foo<Assoc = ()> {} fn call_bar1(_: &dyn Bar) {} fn call_bar2(_: &dyn Bar<Assoc = ()>) {} fn main() { let x: &dyn Bar<Assoc = _> = todo!(); call_bar1(x); //~^ ERROR mismatched types call_bar2(x); //~^ ERROR mismatched types } ``` In this case, we have a user-written associated type bound (`Assoc = _`) which overlaps the bound that comes from the supertrait projection of `Bar` (namely, `Foo<Assoc = ()>`). In a similar way to the two examples above, this causes us to have a projection list mismatch that the compiler is not able to deduplicate. ## Solution ### Do not deduplicate after elaborating projections when lowering `dyn` types The root cause of this issue has to do with mismatches of the deduplicated projection list before and after substitution or inference. This PR aims to avoid these issues by *never* deduplicating the projection list after elaborating the list of projections from the *identity* substituted principal trait ref. For example, ```rust trait Foo<T> { type Assoc; } trait Bar<A, B>: Foo<A, Assoc = A> + Foo<B, Assoc = B> {} ``` When computing the projections for `dyn Bar<(), ()>`, before this PR we'd elaborate `Bar<(), ()>` to find a (deduplicated) projection list of `[Foo<()>::Assoc = ()]`. After this PR, we take the principal trait and use its *identity* substitutions `Bar<A, B>` during elaboration, giving us projections `[Foo<A>::Assoc = A, Foo<B>::Assoc = B]`. Only after this elaboration do we substitute `A = (), B = ()` to get `[Foo<()>::Assoc = (), Foo<()>::Assoc = ()]`. This allows the type to be unified with the projections for `dyn Bar<?A, ?B>`, which are `[Foo<?A>::Assoc = ?A, Foo<?B>::Assoc = ?B]`. This helps us avoid shorcomings 1 noted above. ### Do not deduplicate projections when relating `dyn` types Similarly, we also do not call deduplicate when relating dyn types. This means that the list of projections does not differ depending on if the type has been normalized or not, which should avoid shortcomings 2 noted above. Following from the example above, when relating projection lists like `[Foo<()>::Assoc = (), Foo<()>::Assoc = ()]` and `[Foo<?A>::Assoc = ?A, Foo<?B>::Assoc = ?B]`, the latter won't be deduplicated to a list of length 1 which would immediately fail to relate to the latter which is a list of length 2. ### Implement proper precedence between supertrait and user-written projection bounds when lowering `dyn` types ```rust trait Foo { type Assoc; } trait Bar: Foo<Assoc = ()> {} ``` Given a type like `dyn Foo<Assoc = _>`, we used to previously include *both* the supertrait and user-written associated type bounds in the projection list, giving us `[Foo::Assoc = (), Foo::Assoc = _]`. This would never unify with `dyn Foo`. However, this PR implements a strategy which overwrites the supertrait associated type bound with the one provided by the user, giving us a projection list of `[Foo::Assoc = _]`. Why is this OK? Well, if a user wrote an associated type bound that is unsatisfiable (e.g. `dyn Bar<Assoc = i32>`) then the dyn type would never implement `Bar` or `Foo` anyways. If the user wrote something that is either structurally equal or equal modulo normalization to the supertrait bound, then it should be unaffected. And if the user wrote something that needs inference guidance (e.g. `dyn Bar<Assoc = _>`), then it'll be constrained when proving `dyn Bar<Assoc = _>: Bar`. Importantly, this differs from the strategy in https://github.com/rust-lang/rust/pull/133397, which preferred the *supertrait* bound and ignored the user-written bound. While that's also theoretically justifiable in its own way, it does lead to code which does not (and probably should not) compile either today or after this PR, like: ```rust trait IteratorOfUnit: Iterator<Item = ()> {} impl<T> IteratorOfUnit for T where T: Iterator<Item = ()> {} fn main() { let iter = [()].into_iter(); let iter: &dyn IteratorOfUnit<Item = i32> = &iter; } ``` ### Conclusion This is a far less invasive change compared to #133397, and doesn't necessarily necessitate the addition of new lints or any breakage of existing code. While we could (and possibly should) eventually introduce lints to warn users of redundant or mismatched associated type bounds, we don't *need* to do so as part of fixing this unsoundness, which leads me to believe this is a much safer solution.
This commit is contained in:
commit
326072ac20
19 changed files with 297 additions and 118 deletions
|
@ -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;
|
||||
|
@ -58,9 +58,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
let (trait_bounds, mut projection_bounds) =
|
||||
let (elaborated_trait_bounds, elaborated_projection_bounds) =
|
||||
traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
|
||||
let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = trait_bounds
|
||||
let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds
|
||||
.into_iter()
|
||||
.partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
|
||||
|
||||
|
@ -103,29 +103,81 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
// Map the projection bounds onto a key that makes it easy to remove redundant
|
||||
// bounds that are constrained by supertraits of the principal def id.
|
||||
//
|
||||
// Also make sure we detect conflicting bounds from expanding a trait alias and
|
||||
// also specifying it manually, like:
|
||||
// ```
|
||||
// type Alias = Trait<Assoc = i32>;
|
||||
// let _: &dyn Alias<Assoc = u32> = /* ... */;
|
||||
// ```
|
||||
let mut projection_bounds = FxIndexMap::default();
|
||||
for (proj, proj_span) in elaborated_projection_bounds {
|
||||
let key = (
|
||||
proj.skip_binder().projection_term.def_id,
|
||||
tcx.anonymize_bound_vars(
|
||||
proj.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
|
||||
),
|
||||
);
|
||||
if let Some((old_proj, old_proj_span)) =
|
||||
projection_bounds.insert(key, (proj, proj_span))
|
||||
&& tcx.anonymize_bound_vars(proj) != tcx.anonymize_bound_vars(old_proj)
|
||||
{
|
||||
let item = tcx.item_name(proj.item_def_id());
|
||||
self.dcx()
|
||||
.struct_span_err(
|
||||
span,
|
||||
format!(
|
||||
"conflicting associated type bounds for `{item}` when \
|
||||
expanding trait alias"
|
||||
),
|
||||
)
|
||||
.with_span_label(
|
||||
old_proj_span,
|
||||
format!("`{item}` is specified to be `{}` here", old_proj.term()),
|
||||
)
|
||||
.with_span_label(
|
||||
proj_span,
|
||||
format!("`{item}` is specified to be `{}` here", proj.term()),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
let principal_trait = regular_traits.into_iter().next();
|
||||
|
||||
let mut needed_associated_types = FxIndexSet::default();
|
||||
if let Some((principal_trait, spans)) = &principal_trait {
|
||||
let pred: ty::Predicate<'tcx> = (*principal_trait).upcast(tcx);
|
||||
for ClauseWithSupertraitSpan { pred, supertrait_span } in traits::elaborate(
|
||||
let mut needed_associated_types = vec![];
|
||||
if let Some((principal_trait, ref spans)) = principal_trait {
|
||||
let principal_trait = principal_trait.map_bound(|trait_pred| {
|
||||
assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
|
||||
trait_pred.trait_ref
|
||||
});
|
||||
|
||||
for ClauseWithSupertraitSpan { clause, supertrait_span } in traits::elaborate(
|
||||
tcx,
|
||||
[ClauseWithSupertraitSpan::new(pred, *spans.last().unwrap())],
|
||||
[ClauseWithSupertraitSpan::new(
|
||||
ty::TraitRef::identity(tcx, principal_trait.def_id()).upcast(tcx),
|
||||
*spans.last().unwrap(),
|
||||
)],
|
||||
)
|
||||
.filter_only_self()
|
||||
{
|
||||
debug!("observing object predicate `{pred:?}`");
|
||||
let clause = clause.instantiate_supertrait(tcx, principal_trait);
|
||||
debug!("observing object predicate `{clause:?}`");
|
||||
|
||||
let bound_predicate = pred.kind();
|
||||
let bound_predicate = clause.kind();
|
||||
match bound_predicate.skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
|
||||
ty::ClauseKind::Trait(pred) => {
|
||||
// FIXME(negative_bounds): Handle this correctly...
|
||||
let trait_ref =
|
||||
tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
|
||||
needed_associated_types.extend(
|
||||
tcx.associated_items(trait_ref.def_id())
|
||||
tcx.associated_items(pred.trait_ref.def_id)
|
||||
.in_definition_order()
|
||||
// We only care about associated types.
|
||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
||||
// No RPITITs -- even with `async_fn_in_dyn_trait`, they are implicit.
|
||||
.filter(|item| !item.is_impl_trait_in_trait())
|
||||
// If the associated type has a `where Self: Sized` bound,
|
||||
// we do not need to constrain the associated type.
|
||||
|
@ -133,7 +185,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.map(|item| (item.def_id, trait_ref)),
|
||||
);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
|
||||
ty::ClauseKind::Projection(pred) => {
|
||||
let pred = bound_predicate.rebind(pred);
|
||||
// A `Self` within the original bound will be instantiated with a
|
||||
// `trait_object_dummy_self`, so check for that.
|
||||
|
@ -161,8 +213,15 @@ 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.
|
||||
projection_bounds.push((pred, supertrait_span));
|
||||
let key = (
|
||||
pred.skip_binder().projection_term.def_id,
|
||||
tcx.anonymize_bound_vars(
|
||||
pred.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
|
||||
),
|
||||
);
|
||||
if !projection_bounds.contains_key(&key) {
|
||||
projection_bounds.insert(key, (pred, supertrait_span));
|
||||
}
|
||||
}
|
||||
|
||||
self.check_elaborated_projection_mentions_input_lifetimes(
|
||||
|
@ -182,12 +241,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// types that we expect to be provided by the user, so the following loop
|
||||
// removes all the associated types that have a corresponding `Projection`
|
||||
// clause, either from expanding trait aliases or written by the user.
|
||||
for &(projection_bound, span) in &projection_bounds {
|
||||
for &(projection_bound, span) in projection_bounds.values() {
|
||||
let def_id = projection_bound.item_def_id();
|
||||
let trait_ref = tcx.anonymize_bound_vars(
|
||||
projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)),
|
||||
);
|
||||
needed_associated_types.swap_remove(&(def_id, trait_ref));
|
||||
if tcx.generics_require_sized_self(def_id) {
|
||||
tcx.emit_node_span_lint(
|
||||
UNUSED_ASSOCIATED_TYPE_BOUNDS,
|
||||
|
@ -198,9 +253,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
let mut missing_assoc_types = FxIndexSet::default();
|
||||
let projection_bounds: Vec<_> = needed_associated_types
|
||||
.into_iter()
|
||||
.filter_map(|key| {
|
||||
if let Some(assoc) = projection_bounds.get(&key) {
|
||||
Some(*assoc)
|
||||
} else {
|
||||
missing_assoc_types.insert(key);
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let Err(guar) = self.check_for_required_assoc_tys(
|
||||
principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()),
|
||||
needed_associated_types,
|
||||
missing_assoc_types,
|
||||
potential_assoc_types,
|
||||
hir_bounds,
|
||||
) {
|
||||
|
@ -266,7 +334,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
})
|
||||
});
|
||||
|
||||
let existential_projections = projection_bounds.iter().map(|(bound, _)| {
|
||||
let existential_projections = projection_bounds.into_iter().map(|(bound, _)| {
|
||||
bound.map_bound(|mut b| {
|
||||
assert_eq!(b.projection_term.self_ty(), dummy_self);
|
||||
|
||||
|
@ -291,12 +359,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
})
|
||||
});
|
||||
|
||||
let auto_trait_predicates = auto_traits.into_iter().map(|(trait_pred, _)| {
|
||||
assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive);
|
||||
assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self);
|
||||
let mut auto_trait_predicates: Vec<_> = auto_traits
|
||||
.into_iter()
|
||||
.map(|(trait_pred, _)| {
|
||||
assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive);
|
||||
assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self);
|
||||
|
||||
ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id()))
|
||||
});
|
||||
ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id()))
|
||||
})
|
||||
.collect();
|
||||
auto_trait_predicates.dedup();
|
||||
|
||||
// N.b. principal, projections, auto traits
|
||||
// FIXME: This is actually wrong with multiple principals in regards to symbol mangling
|
||||
|
@ -306,7 +378,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.chain(auto_trait_predicates)
|
||||
.collect::<SmallVec<[_; 8]>>();
|
||||
v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
|
||||
v.dedup();
|
||||
let existential_predicates = tcx.mk_poly_existential_predicates(&v);
|
||||
|
||||
// Use explicitly-specified region bound, unless the bound is missing.
|
||||
|
|
|
@ -79,20 +79,14 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
|
|||
b: Self,
|
||||
) -> 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() {
|
||||
// Fast path for when the auto traits do not match, or if the principals
|
||||
// are from different traits and therefore the projections definitely don't
|
||||
// match up.
|
||||
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(),
|
||||
|
@ -109,8 +103,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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension
|
|||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
use rustc_type_ir::TyKind::*;
|
||||
use rustc_type_ir::visit::TypeVisitableExt;
|
||||
use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind};
|
||||
use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, elaborate};
|
||||
use tracing::instrument;
|
||||
use ty::util::{AsyncDropGlueMorphology, IntTypeExt};
|
||||
|
||||
|
@ -720,6 +720,34 @@ impl<'tcx> Ty<'tcx> {
|
|||
reg: ty::Region<'tcx>,
|
||||
repr: DynKind,
|
||||
) -> Ty<'tcx> {
|
||||
if cfg!(debug_assertions) {
|
||||
let projection_count = obj.projection_bounds().count();
|
||||
let expected_count: usize = obj
|
||||
.principal_def_id()
|
||||
.into_iter()
|
||||
.flat_map(|principal_def_id| {
|
||||
// NOTE: This should agree with `needed_associated_types` in
|
||||
// dyn trait lowering, or else we'll have ICEs.
|
||||
elaborate::supertraits(
|
||||
tcx,
|
||||
ty::Binder::dummy(ty::TraitRef::identity(tcx, principal_def_id)),
|
||||
)
|
||||
.map(|principal| {
|
||||
tcx.associated_items(principal.def_id())
|
||||
.in_definition_order()
|
||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
||||
.filter(|item| !item.is_impl_trait_in_trait())
|
||||
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
|
||||
.count()
|
||||
})
|
||||
})
|
||||
.sum();
|
||||
assert_eq!(
|
||||
projection_count, expected_count,
|
||||
"expected {obj:?} to have {expected_count} projections, \
|
||||
but it has {projection_count}"
|
||||
);
|
||||
}
|
||||
Ty::new(tcx, Dynamic(obj, reg, repr))
|
||||
}
|
||||
|
||||
|
|
|
@ -44,25 +44,22 @@ pub trait Elaboratable<I: Interner> {
|
|||
}
|
||||
|
||||
pub struct ClauseWithSupertraitSpan<I: Interner> {
|
||||
pub pred: I::Predicate,
|
||||
pub clause: I::Clause,
|
||||
// Span of the supertrait predicatae that lead to this clause.
|
||||
pub supertrait_span: I::Span,
|
||||
}
|
||||
impl<I: Interner> ClauseWithSupertraitSpan<I> {
|
||||
pub fn new(pred: I::Predicate, span: I::Span) -> Self {
|
||||
ClauseWithSupertraitSpan { pred, supertrait_span: span }
|
||||
pub fn new(clause: I::Clause, span: I::Span) -> Self {
|
||||
ClauseWithSupertraitSpan { clause, supertrait_span: span }
|
||||
}
|
||||
}
|
||||
impl<I: Interner> Elaboratable<I> for ClauseWithSupertraitSpan<I> {
|
||||
fn predicate(&self) -> <I as Interner>::Predicate {
|
||||
self.pred
|
||||
self.clause.as_predicate()
|
||||
}
|
||||
|
||||
fn child(&self, clause: <I as Interner>::Clause) -> Self {
|
||||
ClauseWithSupertraitSpan {
|
||||
pred: clause.as_predicate(),
|
||||
supertrait_span: self.supertrait_span,
|
||||
}
|
||||
ClauseWithSupertraitSpan { clause, supertrait_span: self.supertrait_span }
|
||||
}
|
||||
|
||||
fn child_with_derived_cause(
|
||||
|
@ -72,7 +69,7 @@ impl<I: Interner> Elaboratable<I> for ClauseWithSupertraitSpan<I> {
|
|||
_parent_trait_pred: crate::Binder<I, crate::TraitPredicate<I>>,
|
||||
_index: usize,
|
||||
) -> Self {
|
||||
ClauseWithSupertraitSpan { pred: clause.as_predicate(), supertrait_span }
|
||||
ClauseWithSupertraitSpan { clause, supertrait_span }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
//@ known-bug: rust-lang/rust#125957
|
||||
#![feature(generic_const_exprs)]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(associated_const_equality)]
|
||||
|
||||
pub struct Equal<const T: usize, const R: usize>();
|
||||
|
||||
pub enum ParseMode {
|
||||
Raw,
|
||||
}
|
||||
pub trait Parse {
|
||||
const PARSE_MODE: ParseMode;
|
||||
}
|
||||
pub trait RenderRaw: Parse<PARSE_MODE = { ParseMode::Raw }> {}
|
||||
|
||||
trait GenericVec<T> {
|
||||
fn unwrap() -> dyn RenderRaw;
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -1,28 +0,0 @@
|
|||
//@ known-bug: #132330
|
||||
//@compile-flags: -Znext-solver=globally
|
||||
|
||||
trait Service {
|
||||
type S;
|
||||
}
|
||||
|
||||
trait Framing {
|
||||
type F;
|
||||
}
|
||||
|
||||
impl Framing for () {
|
||||
type F = ();
|
||||
}
|
||||
|
||||
trait HttpService<F: Framing>: Service<S = F::F> {}
|
||||
|
||||
type BoxService = Box<dyn HttpService<(), S = ()>>;
|
||||
|
||||
fn build_server<F: FnOnce() -> BoxService>(_: F) {}
|
||||
|
||||
fn make_server<F: Framing>() -> Box<dyn HttpService<F, S = F::F>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
build_server(|| make_server())
|
||||
}
|
|
@ -4,5 +4,5 @@ trait I32Iterator = Iterator<Item = i32>;
|
|||
|
||||
fn main() {
|
||||
let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
|
||||
//~^ ERROR expected `IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
|
||||
//~^ ERROR conflicting associated type bounds
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
error[E0271]: expected `IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
|
||||
--> $DIR/associated-types-overridden-binding-2.rs:6:43
|
||||
error: conflicting associated type bounds for `Item` when expanding trait alias
|
||||
--> $DIR/associated-types-overridden-binding-2.rs:6:13
|
||||
|
|
||||
LL | trait I32Iterator = Iterator<Item = i32>;
|
||||
| ---------- `Item` is specified to be `i32` here
|
||||
...
|
||||
LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
|
||||
|
|
||||
= note: required for the cast from `&std::vec::IntoIter<u32>` to `&dyn Iterator<Item = u32, Item = i32>`
|
||||
| ^^^^^^^^^^^^^^^^----------^
|
||||
| |
|
||||
| `Item` is specified to be `u32` here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0271`.
|
||||
|
|
|
@ -8,4 +8,5 @@ trait U32Iterator = I32Iterator<Item = u32>; //~ ERROR type annotations needed
|
|||
|
||||
fn main() {
|
||||
let _: &dyn I32Iterator<Item = u32>;
|
||||
//~^ ERROR conflicting associated type bounds
|
||||
}
|
||||
|
|
|
@ -22,6 +22,17 @@ note: required by a bound in `I32Iterator`
|
|||
LL | trait I32Iterator = Iterator<Item = i32>;
|
||||
| ^^^^^^^^^^ required by this bound in `I32Iterator`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: conflicting associated type bounds for `Item` when expanding trait alias
|
||||
--> $DIR/associated-types-overridden-binding.rs:10:13
|
||||
|
|
||||
LL | trait I32Iterator = Iterator<Item = i32>;
|
||||
| ---------- `Item` is specified to be `i32` here
|
||||
...
|
||||
LL | let _: &dyn I32Iterator<Item = u32>;
|
||||
| ^^^^^^^^^^^^^^^^----------^
|
||||
| |
|
||||
| `Item` is specified to be `u32` here
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0284`.
|
||||
|
|
18
tests/ui/closures/deduce-from-object-supertrait.rs
Normal file
18
tests/ui/closures/deduce-from-object-supertrait.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
//@ check-pass
|
||||
|
||||
// This test checks that we look at consider the super traits of trait objects
|
||||
// when deducing closure signatures.
|
||||
|
||||
trait Foo: Fn(Bar) {}
|
||||
impl<T> Foo for T where T: Fn(Bar) {}
|
||||
|
||||
struct Bar;
|
||||
impl Bar {
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x: &dyn Foo = &|x| {
|
||||
x.bar();
|
||||
};
|
||||
}
|
21
tests/ui/dyn-compatibility/multiple-supers-should-work.rs
Normal file
21
tests/ui/dyn-compatibility/multiple-supers-should-work.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
//@ check-pass
|
||||
|
||||
// We previously incorrectly deduplicated the list of projection bounds
|
||||
// of trait objects, causing us to incorrectly reject this code, cc #136458.
|
||||
|
||||
trait Sup<T> {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl<T> Sup<T> for () {
|
||||
type Assoc = T;
|
||||
}
|
||||
|
||||
trait Trait<A, B>: Sup<A, Assoc = A> + Sup<B, Assoc = B> {}
|
||||
|
||||
impl<T, U> Trait<T, U> for () {}
|
||||
|
||||
fn main() {
|
||||
let x: &dyn Trait<(), _> = &();
|
||||
let y: &dyn Trait<_, ()> = x;
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
//@ known-bug: rust-lang/rust#126944
|
||||
//@ check-pass
|
||||
|
||||
// Regression test for #126944.
|
||||
|
||||
// Step 1: Create two names for a single type: `Thing` and `AlsoThing`
|
||||
|
||||
struct Thing;
|
||||
struct Dummy;
|
||||
pub trait DummyTrait {
|
||||
trait DummyTrait {
|
||||
type DummyType;
|
||||
}
|
||||
impl DummyTrait for Dummy {
|
||||
|
@ -13,7 +16,7 @@ type AlsoThing = <Dummy as DummyTrait>::DummyType;
|
|||
|
||||
// Step 2: Create names for a single trait object type: `TraitObject` and `AlsoTraitObject`
|
||||
|
||||
pub trait SomeTrait {
|
||||
trait SomeTrait {
|
||||
type Item;
|
||||
}
|
||||
type TraitObject = dyn SomeTrait<Item = AlsoThing>;
|
||||
|
@ -21,12 +24,12 @@ type AlsoTraitObject = dyn SomeTrait<Item = Thing>;
|
|||
|
||||
// Step 3: Force the compiler to check whether the two names are the same type
|
||||
|
||||
pub trait Supertrait {
|
||||
trait Supertrait {
|
||||
type Foo;
|
||||
}
|
||||
pub trait Subtrait: Supertrait<Foo = TraitObject> {}
|
||||
trait Subtrait: Supertrait<Foo = TraitObject> {}
|
||||
|
||||
pub trait HasOutput<A: ?Sized> {
|
||||
trait HasOutput<A: ?Sized> {
|
||||
type Output;
|
||||
}
|
||||
|
||||
|
@ -36,3 +39,5 @@ where
|
|||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,32 @@
|
|||
// Regression test for #133361.
|
||||
|
||||
trait Sup<T> {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl<T> Sup<T> for () {
|
||||
type Assoc = T;
|
||||
}
|
||||
impl<T, U> Dyn<T, U> for () {}
|
||||
|
||||
trait Dyn<A, B>: Sup<A, Assoc = A> + Sup<B, Assoc = B> {}
|
||||
|
||||
trait Trait {
|
||||
type Assoc;
|
||||
}
|
||||
impl Trait for dyn Dyn<(), ()> {
|
||||
type Assoc = &'static str;
|
||||
}
|
||||
impl<A, B> Trait for dyn Dyn<A, B> {
|
||||
//~^ ERROR conflicting implementations of trait `Trait` for type `(dyn Dyn<(), ()> + 'static)`
|
||||
type Assoc = usize;
|
||||
}
|
||||
|
||||
fn call<A, B>(x: usize) -> <dyn Dyn<A, B> as Trait>::Assoc {
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x: &'static str = call::<(), ()>(0xDEADBEEF);
|
||||
println!("{x}");
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
error[E0119]: conflicting implementations of trait `Trait` for type `(dyn Dyn<(), ()> + 'static)`
|
||||
--> $DIR/incomplete-multiple-super-projection.rs:20:1
|
||||
|
|
||||
LL | impl Trait for dyn Dyn<(), ()> {
|
||||
| ------------------------------ first implementation here
|
||||
...
|
||||
LL | impl<A, B> Trait for dyn Dyn<A, B> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Dyn<(), ()> + 'static)`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0119`.
|
|
@ -1,4 +1,4 @@
|
|||
//@ known-bug: #79590
|
||||
//@ check-pass
|
||||
|
||||
trait Database: Restriction<Inner = u32> {}
|
||||
|
24
tests/ui/traits/object/outlives-super-proj.rs
Normal file
24
tests/ui/traits/object/outlives-super-proj.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
//@ check-pass
|
||||
|
||||
// Make sure that we still deduce outlives bounds from supertrait projections
|
||||
// and require them for well-formedness.
|
||||
|
||||
trait Trait {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
trait Bar {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
trait Foo<'a, T: 'a>: Bar<Assoc = &'a T> {
|
||||
|
||||
}
|
||||
|
||||
fn outlives<'a, T: 'a>() {}
|
||||
|
||||
fn implied_outlives<'a, T: Trait>(x: &dyn Foo<'a, T::Assoc>) {
|
||||
outlives::<'a, T::Assoc>();
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -154,12 +154,12 @@ error[E0308]: mismatched types
|
|||
--> $DIR/pretty.rs:41:56
|
||||
|
|
||||
LL | fn dyn_has_gat(x: &dyn HasGat<u8, Assoc<bool> = ()>) { x }
|
||||
| - ^ expected `()`, found `&dyn HasGat<u8, Assoc<bool> = ()>`
|
||||
| - ^ expected `()`, found `&dyn HasGat<u8>`
|
||||
| |
|
||||
| help: try adding a return type: `-> &dyn HasGat<u8, Assoc<bool> = ()>`
|
||||
| help: try adding a return type: `-> &dyn HasGat<u8>`
|
||||
|
|
||||
= note: expected unit type `()`
|
||||
found reference `&dyn HasGat<u8, Assoc<bool> = ()>`
|
||||
found reference `&dyn HasGat<u8>`
|
||||
|
||||
error: aborting due to 14 previous errors; 1 warning emitted
|
||||
|
||||
|
|
12
tests/ui/traits/object/redundant.rs
Normal file
12
tests/ui/traits/object/redundant.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
//@ check-pass
|
||||
|
||||
trait Foo: Bar<Out = ()> {}
|
||||
trait Bar {
|
||||
type Out;
|
||||
}
|
||||
|
||||
fn w(x: &dyn Foo<Out = ()>) {
|
||||
let x: &dyn Foo = x;
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue