Auto merge of #73905 - matthewjasper:projection-bounds-2, r=nikomatsakis
Separate projection bounds and predicates Follow up to #72788. - Rename `projection_predicates` to `item_bounds` - Separate bounds on associated types (the things after the `:` in `type X: ...`) and opaque types (the things after `impl`) from predicates. - Projection candidates now have the correct nested obligations - Trait object candidates now check that the associated types on the trait object satisfy their bounds as nested obligations - Type alias impl trait types are now checked (#73035) - `feature(generic_associated_types)` no longer changes how we handle bounds (#73816) Opening for a perf and crater runs. r? `@nikomatsakis`
This commit is contained in:
commit
08e2d46166
@ -432,17 +432,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.with_catch_scope(body.id, |this| {
|
||||
let mut block = this.lower_block_noalloc(body, true);
|
||||
|
||||
let try_span = this.mark_span_with_reason(
|
||||
DesugaringKind::TryBlock,
|
||||
body.span,
|
||||
this.allow_try_trait.clone(),
|
||||
);
|
||||
|
||||
// Final expression of the block (if present) or `()` with span at the end of block
|
||||
let tail_expr = block
|
||||
.expr
|
||||
.take()
|
||||
.unwrap_or_else(|| this.expr_unit(this.sess.source_map().end_point(try_span)));
|
||||
let (try_span, tail_expr) = if let Some(expr) = block.expr.take() {
|
||||
(
|
||||
this.mark_span_with_reason(
|
||||
DesugaringKind::TryBlock,
|
||||
expr.span,
|
||||
this.allow_try_trait.clone(),
|
||||
),
|
||||
expr,
|
||||
)
|
||||
} else {
|
||||
let try_span = this.mark_span_with_reason(
|
||||
DesugaringKind::TryBlock,
|
||||
this.sess.source_map().end_point(body.span),
|
||||
this.allow_try_trait.clone(),
|
||||
);
|
||||
|
||||
(try_span, this.expr_unit(try_span))
|
||||
};
|
||||
|
||||
let ok_wrapped_span =
|
||||
this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None);
|
||||
@ -1553,7 +1561,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir::LangItem::TryFromError,
|
||||
unstable_span,
|
||||
from_expr,
|
||||
try_span,
|
||||
unstable_span,
|
||||
);
|
||||
let thin_attrs = ThinVec::from(attrs);
|
||||
let catch_scope = self.catch_scopes.last().copied();
|
||||
|
@ -5,37 +5,29 @@ as the `collect` method for `Iterator`s.
|
||||
For example:
|
||||
|
||||
```compile_fail,E0284
|
||||
fn foo() -> Result<bool, ()> {
|
||||
let results = [Ok(true), Ok(false), Err(())].iter().cloned();
|
||||
let v: Vec<bool> = results.collect()?;
|
||||
// Do things with v...
|
||||
Ok(true)
|
||||
fn main() {
|
||||
let n: u32 = 1;
|
||||
let mut d: u64 = 2;
|
||||
d = d + n.into();
|
||||
}
|
||||
```
|
||||
|
||||
Here we have an iterator `results` over `Result<bool, ()>`.
|
||||
Hence, `results.collect()` can return any type implementing
|
||||
`FromIterator<Result<bool, ()>>`. On the other hand, the
|
||||
`?` operator can accept any type implementing `Try`.
|
||||
Here we have an addition of `d` and `n.into()`. Hence, `n.into()` can return
|
||||
any type `T` where `u64: Add<T>`. On the other hand, the `into` method can
|
||||
return any type where `u32: Into<T>`.
|
||||
|
||||
The author of this code probably wants `collect()` to return a
|
||||
`Result<Vec<bool>, ()>`, but the compiler can't be sure
|
||||
that there isn't another type `T` implementing both `Try` and
|
||||
`FromIterator<Result<bool, ()>>` in scope such that
|
||||
`T::Ok == Vec<bool>`. Hence, this code is ambiguous and an error
|
||||
is returned.
|
||||
The author of this code probably wants `into()` to return a `u64`, but the
|
||||
compiler can't be sure that there isn't another type `T` where both
|
||||
`u32: Into<T>` and `u64: Add<T>`.
|
||||
|
||||
To resolve this error, use a concrete type for the intermediate expression:
|
||||
|
||||
```
|
||||
fn foo() -> Result<bool, ()> {
|
||||
let results = [Ok(true), Ok(false), Err(())].iter().cloned();
|
||||
let v = {
|
||||
let temp: Result<Vec<bool>, ()> = results.collect();
|
||||
temp?
|
||||
};
|
||||
// Do things with v...
|
||||
Ok(true)
|
||||
fn main() {
|
||||
let n: u32 = 1;
|
||||
let mut d: u64 = 2;
|
||||
let m: u64 = n.into();
|
||||
d = d + m;
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
//! the end of the file for details.
|
||||
|
||||
use super::combine::CombineFields;
|
||||
use super::{HigherRankedType, InferCtxt, PlaceholderMap};
|
||||
use super::{HigherRankedType, InferCtxt};
|
||||
|
||||
use crate::infer::CombinedSnapshot;
|
||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
@ -33,7 +33,7 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
|
||||
self.infcx.commit_if_ok(|_| {
|
||||
// First, we instantiate each bound region in the supertype with a
|
||||
// fresh placeholder region.
|
||||
let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(&b);
|
||||
let b_prime = self.infcx.replace_bound_vars_with_placeholders(&b);
|
||||
|
||||
// Next, we instantiate each bound region in the subtype
|
||||
// with a fresh region variable. These region variables --
|
||||
@ -66,10 +66,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
/// the [rustc dev guide].
|
||||
///
|
||||
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
|
||||
pub fn replace_bound_vars_with_placeholders<T>(
|
||||
&self,
|
||||
binder: &ty::Binder<T>,
|
||||
) -> (T, PlaceholderMap<'tcx>)
|
||||
pub fn replace_bound_vars_with_placeholders<T>(&self, binder: &ty::Binder<T>) -> T
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
@ -122,7 +119,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
next_universe, binder, result, map,
|
||||
);
|
||||
|
||||
(result, map)
|
||||
result
|
||||
}
|
||||
|
||||
/// See `infer::region_constraints::RegionConstraintCollector::leak_check`.
|
||||
|
@ -351,11 +351,6 @@ pub struct InferCtxt<'a, 'tcx> {
|
||||
universe: Cell<ty::UniverseIndex>,
|
||||
}
|
||||
|
||||
/// A map returned by `replace_bound_vars_with_placeholders()`
|
||||
/// indicating the placeholder region that each late-bound region was
|
||||
/// replaced with.
|
||||
pub type PlaceholderMap<'tcx> = BTreeMap<ty::BoundRegion, ty::Region<'tcx>>;
|
||||
|
||||
/// See the `error_reporting` module for more details.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, TypeFoldable)]
|
||||
pub enum ValuePairs<'tcx> {
|
||||
@ -992,7 +987,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
Some(self.commit_if_ok(|_snapshot| {
|
||||
let (ty::SubtypePredicate { a_is_expected, a, b }, _) =
|
||||
let ty::SubtypePredicate { a_is_expected, a, b } =
|
||||
self.replace_bound_vars_with_placeholders(&predicate);
|
||||
|
||||
let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
|
||||
@ -1007,7 +1002,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
|
||||
) -> UnitResult<'tcx> {
|
||||
self.commit_if_ok(|_snapshot| {
|
||||
let (ty::OutlivesPredicate(r_a, r_b), _) =
|
||||
let ty::OutlivesPredicate(r_a, r_b) =
|
||||
self.replace_bound_vars_with_placeholders(&predicate);
|
||||
let origin = SubregionOrigin::from_obligation_cause(cause, || {
|
||||
RelateRegionParamBound(cause.span)
|
||||
|
@ -328,8 +328,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||
assoc_item_def_id: DefId,
|
||||
) -> impl Iterator<Item = ty::Region<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
let predicates = tcx.projection_predicates(assoc_item_def_id);
|
||||
predicates
|
||||
let bounds = tcx.item_bounds(assoc_item_def_id);
|
||||
bounds
|
||||
.into_iter()
|
||||
.filter_map(|p| p.to_opt_type_outlives())
|
||||
.filter_map(|p| p.no_bound_vars())
|
||||
|
@ -4,7 +4,6 @@ use crate::traits::{Obligation, ObligationCause, PredicateObligation};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_middle::ty::outlives::Component;
|
||||
use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness};
|
||||
use rustc_span::Span;
|
||||
|
||||
pub fn anonymize_predicate<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
@ -94,7 +93,11 @@ pub fn elaborate_predicates<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
|
||||
) -> Elaborator<'tcx> {
|
||||
let obligations = predicates.map(|predicate| predicate_obligation(predicate, None)).collect();
|
||||
let obligations = predicates
|
||||
.map(|predicate| {
|
||||
predicate_obligation(predicate, ty::ParamEnv::empty(), ObligationCause::dummy())
|
||||
})
|
||||
.collect();
|
||||
elaborate_obligations(tcx, obligations)
|
||||
}
|
||||
|
||||
@ -109,15 +112,10 @@ pub fn elaborate_obligations<'tcx>(
|
||||
|
||||
fn predicate_obligation<'tcx>(
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
span: Option<Span>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
) -> PredicateObligation<'tcx> {
|
||||
let cause = if let Some(span) = span {
|
||||
ObligationCause::dummy_with_span(span)
|
||||
} else {
|
||||
ObligationCause::dummy()
|
||||
};
|
||||
|
||||
Obligation { cause, param_env: ty::ParamEnv::empty(), recursion_depth: 0, predicate }
|
||||
Obligation { cause, param_env, recursion_depth: 0, predicate }
|
||||
}
|
||||
|
||||
impl Elaborator<'tcx> {
|
||||
@ -133,10 +131,11 @@ impl Elaborator<'tcx> {
|
||||
// Get predicates declared on the trait.
|
||||
let predicates = tcx.super_predicates_of(data.def_id());
|
||||
|
||||
let obligations = predicates.predicates.iter().map(|&(pred, span)| {
|
||||
let obligations = predicates.predicates.iter().map(|&(pred, _)| {
|
||||
predicate_obligation(
|
||||
pred.subst_supertrait(tcx, &ty::Binder::bind(data.trait_ref)),
|
||||
Some(span),
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
)
|
||||
});
|
||||
debug!("super_predicates: data={:?}", data);
|
||||
@ -233,7 +232,13 @@ impl Elaborator<'tcx> {
|
||||
})
|
||||
.map(|predicate_kind| predicate_kind.to_predicate(tcx))
|
||||
.filter(|&predicate| visited.insert(predicate))
|
||||
.map(|predicate| predicate_obligation(predicate, None)),
|
||||
.map(|predicate| {
|
||||
predicate_obligation(
|
||||
predicate,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
)
|
||||
}),
|
||||
);
|
||||
}
|
||||
ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
|
||||
|
@ -200,7 +200,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
||||
ty::Adt(def, _) => check_must_use_def(cx, def.did, span, descr_pre, descr_post),
|
||||
ty::Opaque(def, _) => {
|
||||
let mut has_emitted = false;
|
||||
for (predicate, _) in cx.tcx.predicates_of(def).predicates {
|
||||
for &(predicate, _) in cx.tcx.explicit_item_bounds(def) {
|
||||
// We only look at the `DefId`, so it is safe to skip the binder here.
|
||||
if let ty::PredicateAtom::Trait(ref poly_trait_predicate, _) =
|
||||
predicate.skip_binders()
|
||||
|
@ -937,7 +937,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||
.tables
|
||||
.inferred_outlives
|
||||
.get(self, item_id)
|
||||
.map(|predicates| predicates.decode((self, tcx)))
|
||||
.map(|predicates| tcx.arena.alloc_from_iter(predicates.decode((self, tcx))))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
@ -949,6 +949,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||
self.root.tables.super_predicates.get(self, item_id).unwrap().decode((self, tcx))
|
||||
}
|
||||
|
||||
fn get_explicit_item_bounds(
|
||||
&self,
|
||||
item_id: DefIndex,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
|
||||
self.root
|
||||
.tables
|
||||
.explicit_item_bounds
|
||||
.get(self, item_id)
|
||||
.map(|bounds| tcx.arena.alloc_from_iter(bounds.decode((self, tcx))))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn get_generics(&self, item_id: DefIndex, sess: &Session) -> ty::Generics {
|
||||
self.root.tables.generics.get(self, item_id).unwrap().decode((self, sess))
|
||||
}
|
||||
|
@ -89,6 +89,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
|
||||
explicit_predicates_of => { cdata.get_explicit_predicates(def_id.index, tcx) }
|
||||
inferred_outlives_of => { cdata.get_inferred_outlives(def_id.index, tcx) }
|
||||
super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) }
|
||||
explicit_item_bounds => { cdata.get_explicit_item_bounds(def_id.index, tcx) }
|
||||
trait_def => { cdata.get_trait_def(def_id.index, tcx.sess) }
|
||||
adt_def => { cdata.get_adt_def(def_id.index, tcx) }
|
||||
adt_destructor => {
|
||||
|
@ -965,6 +965,14 @@ impl EncodeContext<'a, 'tcx> {
|
||||
record!(self.tables.super_predicates[def_id] <- self.tcx.super_predicates_of(def_id));
|
||||
}
|
||||
|
||||
fn encode_explicit_item_bounds(&mut self, def_id: DefId) {
|
||||
debug!("EncodeContext::encode_explicit_item_bounds({:?})", def_id);
|
||||
let bounds = self.tcx.explicit_item_bounds(def_id);
|
||||
if !bounds.is_empty() {
|
||||
record!(self.tables.explicit_item_bounds[def_id] <- bounds);
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_info_for_trait_item(&mut self, def_id: DefId) {
|
||||
debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id);
|
||||
let tcx = self.tcx;
|
||||
@ -1017,7 +1025,10 @@ impl EncodeContext<'a, 'tcx> {
|
||||
has_self: trait_item.fn_has_self_parameter,
|
||||
}))
|
||||
}
|
||||
ty::AssocKind::Type => EntryKind::AssocType(container),
|
||||
ty::AssocKind::Type => {
|
||||
self.encode_explicit_item_bounds(def_id);
|
||||
EntryKind::AssocType(container)
|
||||
}
|
||||
});
|
||||
record!(self.tables.visibility[def_id] <- trait_item.vis);
|
||||
record!(self.tables.span[def_id] <- ast_item.span);
|
||||
@ -1255,7 +1266,10 @@ impl EncodeContext<'a, 'tcx> {
|
||||
hir::ItemKind::ForeignMod(_) => EntryKind::ForeignMod,
|
||||
hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm,
|
||||
hir::ItemKind::TyAlias(..) => EntryKind::Type,
|
||||
hir::ItemKind::OpaqueTy(..) => EntryKind::OpaqueTy,
|
||||
hir::ItemKind::OpaqueTy(..) => {
|
||||
self.encode_explicit_item_bounds(def_id);
|
||||
EntryKind::OpaqueTy
|
||||
}
|
||||
hir::ItemKind::Enum(..) => EntryKind::Enum(self.tcx.adt_def(def_id).repr),
|
||||
hir::ItemKind::Struct(ref struct_def, _) => {
|
||||
let adt_def = self.tcx.adt_def(def_id);
|
||||
|
@ -295,13 +295,11 @@ define_tables! {
|
||||
generics: Table<DefIndex, Lazy<ty::Generics>>,
|
||||
explicit_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
|
||||
expn_that_defined: Table<DefIndex, Lazy<ExpnId>>,
|
||||
// FIXME(eddyb) this would ideally be `Lazy<[...]>` but `ty::Predicate`
|
||||
// doesn't handle shorthands in its own (de)serialization impls,
|
||||
// as it's an `enum` for which we want to derive (de)serialization,
|
||||
// so the `ty::codec` APIs handle the whole `&'tcx [...]` at once.
|
||||
// Also, as an optimization, a missing entry indicates an empty `&[]`.
|
||||
inferred_outlives: Table<DefIndex, Lazy!(&'tcx [(ty::Predicate<'tcx>, Span)])>,
|
||||
// As an optimization, a missing entry indicates an empty `&[]`.
|
||||
inferred_outlives: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
|
||||
super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
|
||||
// As an optimization, a missing entry indicates an empty `&[]`.
|
||||
explicit_item_bounds: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
|
||||
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
|
||||
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
|
||||
mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
|
||||
|
@ -156,12 +156,11 @@ rustc_queries! {
|
||||
cache_on_disk_if { key.is_local() }
|
||||
}
|
||||
|
||||
/// Returns the list of predicates that can be used for
|
||||
/// `SelectionCandidate::ProjectionCandidate` and
|
||||
/// Returns the list of bounds that can be used for
|
||||
/// `SelectionCandidate::ProjectionCandidate(_)` and
|
||||
/// `ProjectionTyCandidate::TraitDef`.
|
||||
/// Specifically this is the bounds (equivalent to) those
|
||||
/// written on the trait's type definition, or those
|
||||
/// after the `impl` keyword
|
||||
/// Specifically this is the bounds written on the trait's type
|
||||
/// definition, or those after the `impl` keyword
|
||||
///
|
||||
/// type X: Bound + 'lt
|
||||
/// ^^^^^^^^^^^
|
||||
@ -169,8 +168,30 @@ rustc_queries! {
|
||||
/// ^^^^^^^^^^^^^^^
|
||||
///
|
||||
/// `key` is the `DefId` of the associated type or opaque type.
|
||||
query projection_predicates(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> {
|
||||
desc { |tcx| "finding projection predicates for `{}`", tcx.def_path_str(key) }
|
||||
///
|
||||
/// Bounds from the parent (e.g. with nested impl trait) are not included.
|
||||
query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
|
||||
desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
/// Elaborated version of the predicates from `explicit_item_bounds`.
|
||||
///
|
||||
/// Example for
|
||||
///
|
||||
/// trait MyTrait {
|
||||
/// type MyAType: Eq + ?Sized`
|
||||
/// }
|
||||
///
|
||||
/// `explicit_item_bounds` returns `[<Self as MyTrait>::MyAType: Eq]`,
|
||||
/// and `item_bounds` returns
|
||||
/// [
|
||||
/// <Self as Trait>::MyAType: Eq,
|
||||
/// <Self as Trait>::MyAType: PartialEq<<Self as Trait>::MyAType>
|
||||
/// ]
|
||||
///
|
||||
/// Bounds from the parent (e.g. with nested impl trait) are not included.
|
||||
query item_bounds(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> {
|
||||
desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
query projection_ty_from_predicates(key: (DefId, DefId)) -> Option<ty::ProjectionTy<'tcx>> {
|
||||
@ -370,6 +391,24 @@ rustc_queries! {
|
||||
desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
/// Returns everything that looks like a predicate written explicitly
|
||||
/// by the user on a trait item.
|
||||
///
|
||||
/// Traits are unusual, because predicates on associated types are
|
||||
/// converted into bounds on that type for backwards compatibility:
|
||||
///
|
||||
/// trait X where Self::U: Copy { type U; }
|
||||
///
|
||||
/// becomes
|
||||
///
|
||||
/// trait X { type U: Copy; }
|
||||
///
|
||||
/// `explicit_predicates_of` and `explicit_item_bounds` will then take
|
||||
/// the appropriate subsets of the predicates here.
|
||||
query trait_explicit_predicates_and_bounds(key: LocalDefId) -> ty::GenericPredicates<'tcx> {
|
||||
desc { |tcx| "computing explicit predicates of trait `{}`", tcx.def_path_str(key.to_def_id()) }
|
||||
}
|
||||
|
||||
/// Returns the predicates written explicitly by the user.
|
||||
query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
|
||||
desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) }
|
||||
|
@ -105,9 +105,10 @@ pub enum SelectionCandidate<'tcx> {
|
||||
ImplCandidate(DefId),
|
||||
AutoImplCandidate(DefId),
|
||||
|
||||
/// This is a trait matching with a projected type as `Self`, and
|
||||
/// we found an applicable bound in the trait definition.
|
||||
ProjectionCandidate,
|
||||
/// This is a trait matching with a projected type as `Self`, and we found
|
||||
/// an applicable bound in the trait definition. The `usize` is an index
|
||||
/// into the list returned by `tcx.item_bounds`.
|
||||
ProjectionCandidate(usize),
|
||||
|
||||
/// Implementation of a `Fn`-family trait by one of the anonymous types
|
||||
/// generated for a `||` expression.
|
||||
|
@ -607,12 +607,13 @@ pub trait PrettyPrinter<'tcx>:
|
||||
}
|
||||
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
|
||||
// by looking up the projections associated with the def_id.
|
||||
let bounds = self.tcx().predicates_of(def_id).instantiate(self.tcx(), substs);
|
||||
let bounds = self.tcx().explicit_item_bounds(def_id);
|
||||
|
||||
let mut first = true;
|
||||
let mut is_sized = false;
|
||||
p!("impl");
|
||||
for predicate in bounds.predicates {
|
||||
for (predicate, _) in bounds {
|
||||
let predicate = predicate.subst(self.tcx(), substs);
|
||||
// Note: We can't use `to_opt_poly_trait_ref` here as `predicate`
|
||||
// may contain unbound variables. We therefore do this manually.
|
||||
//
|
||||
|
@ -1513,6 +1513,9 @@ impl<'tcx> ExistentialProjection<'tcx> {
|
||||
/// then this function would return a `exists T. T: Iterator` existential trait
|
||||
/// reference.
|
||||
pub fn trait_ref(&self, tcx: TyCtxt<'_>) -> ty::ExistentialTraitRef<'tcx> {
|
||||
// FIXME(generic_associated_types): substs is the substs of the
|
||||
// associated type, which should be truncated to get the correct substs
|
||||
// for the trait.
|
||||
let def_id = tcx.associated_item(self.item_def_id).container.id();
|
||||
ty::ExistentialTraitRef { def_id, substs: self.substs }
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ use rustc_infer::infer::{
|
||||
error_reporting::unexpected_hidden_region_diagnostic, NLLRegionVariableOrigin,
|
||||
};
|
||||
use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
|
||||
use rustc_middle::ty::subst::Subst;
|
||||
use rustc_middle::ty::{self, RegionVid, Ty};
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::Span;
|
||||
@ -585,14 +586,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
//
|
||||
// eg. check for `impl Trait + 'static` instead of `impl Trait`.
|
||||
let has_static_predicate = {
|
||||
let predicates_of = self.infcx.tcx.predicates_of(did);
|
||||
let bounds = predicates_of.instantiate(self.infcx.tcx, substs);
|
||||
let bounds = self.infcx.tcx.explicit_item_bounds(did);
|
||||
|
||||
let mut found = false;
|
||||
for predicate in bounds.predicates {
|
||||
for (bound, _) in bounds {
|
||||
if let ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(_, r)) =
|
||||
predicate.skip_binders()
|
||||
bound.skip_binders()
|
||||
{
|
||||
let r = r.subst(self.infcx.tcx, substs);
|
||||
if let ty::RegionKind::ReStatic = r {
|
||||
found = true;
|
||||
break;
|
||||
|
@ -194,11 +194,14 @@ where
|
||||
// The intent is to treat `impl Trait1 + Trait2` identically to
|
||||
// `dyn Trait1 + Trait2`. Therefore we ignore def-id of the opaque type itself
|
||||
// (it either has no visibility, or its visibility is insignificant, like
|
||||
// visibilities of type aliases) and recurse into predicates instead to go
|
||||
// visibilities of type aliases) and recurse into bounds instead to go
|
||||
// through the trait list (default type visitor doesn't visit those traits).
|
||||
// All traits in the list are considered the "primary" part of the type
|
||||
// and are visited by shallow visitors.
|
||||
if self.visit_predicates(tcx.predicates_of(def_id)) {
|
||||
if self.visit_predicates(ty::GenericPredicates {
|
||||
parent: None,
|
||||
predicates: tcx.explicit_item_bounds(def_id),
|
||||
}) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1800,6 +1803,14 @@ impl SearchInterfaceForPrivateItemsVisitor<'tcx> {
|
||||
self
|
||||
}
|
||||
|
||||
fn bounds(&mut self) -> &mut Self {
|
||||
self.visit_predicates(ty::GenericPredicates {
|
||||
parent: None,
|
||||
predicates: self.tcx.explicit_item_bounds(self.item_def_id),
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
fn ty(&mut self) -> &mut Self {
|
||||
self.visit(self.tcx.type_of(self.item_def_id));
|
||||
self
|
||||
@ -1975,7 +1986,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
|
||||
hir::ItemKind::OpaqueTy(..) => {
|
||||
// `ty()` for opaque types is the underlying type,
|
||||
// it's not a part of interface, so we skip it.
|
||||
self.check(item.hir_id, item_visibility).generics().predicates();
|
||||
self.check(item.hir_id, item_visibility).generics().bounds();
|
||||
}
|
||||
hir::ItemKind::Trait(.., trait_item_refs) => {
|
||||
self.check(item.hir_id, item_visibility).generics().predicates();
|
||||
@ -1987,6 +1998,10 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
|
||||
trait_item_ref.defaultness,
|
||||
item_visibility,
|
||||
);
|
||||
|
||||
if let AssocItemKind::Type = trait_item_ref.kind {
|
||||
self.check(trait_item_ref.id.hir_id, item_visibility).bounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ItemKind::TraitAlias(..) => {
|
||||
|
@ -10,7 +10,7 @@ use rustc_infer::infer::free_regions::FreeRegionRelations;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::{self, InferCtxt, InferOk};
|
||||
use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_session::config::nightly_options;
|
||||
use rustc_span::Span;
|
||||
@ -428,14 +428,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
|
||||
// If there are required region bounds, we can use them.
|
||||
if opaque_defn.has_required_region_bounds {
|
||||
let predicates_of = tcx.predicates_of(def_id);
|
||||
debug!("constrain_opaque_type: predicates: {:#?}", predicates_of,);
|
||||
let bounds = predicates_of.instantiate(tcx, opaque_defn.substs);
|
||||
let bounds = tcx.explicit_item_bounds(def_id);
|
||||
debug!("constrain_opaque_type: predicates: {:#?}", bounds);
|
||||
let bounds: Vec<_> =
|
||||
bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_defn.substs)).collect();
|
||||
debug!("constrain_opaque_type: bounds={:#?}", bounds);
|
||||
let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs);
|
||||
|
||||
let required_region_bounds =
|
||||
required_region_bounds(tcx, opaque_type, bounds.predicates.into_iter());
|
||||
required_region_bounds(tcx, opaque_type, bounds.into_iter());
|
||||
debug_assert!(!required_region_bounds.is_empty());
|
||||
|
||||
for required_region in required_region_bounds {
|
||||
@ -1112,9 +1113,10 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
||||
let ty_var = infcx
|
||||
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
|
||||
|
||||
let predicates_of = tcx.predicates_of(def_id);
|
||||
debug!("instantiate_opaque_types: predicates={:#?}", predicates_of,);
|
||||
let bounds = predicates_of.instantiate(tcx, substs);
|
||||
let item_bounds = tcx.explicit_item_bounds(def_id);
|
||||
debug!("instantiate_opaque_types: bounds={:#?}", item_bounds);
|
||||
let bounds: Vec<_> =
|
||||
item_bounds.iter().map(|(bound, _)| bound.subst(tcx, substs)).collect();
|
||||
|
||||
let param_env = tcx.param_env(def_id);
|
||||
let InferOk { value: bounds, obligations } =
|
||||
@ -1123,8 +1125,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
||||
|
||||
debug!("instantiate_opaque_types: bounds={:?}", bounds);
|
||||
|
||||
let required_region_bounds =
|
||||
required_region_bounds(tcx, ty, bounds.predicates.iter().cloned());
|
||||
let required_region_bounds = required_region_bounds(tcx, ty, bounds.iter().copied());
|
||||
debug!("instantiate_opaque_types: required_region_bounds={:?}", required_region_bounds);
|
||||
|
||||
// Make sure that we are in fact defining the *entire* type
|
||||
@ -1153,7 +1154,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
||||
);
|
||||
debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
|
||||
|
||||
for predicate in &bounds.predicates {
|
||||
for predicate in &bounds {
|
||||
if let ty::PredicateAtom::Projection(projection) = predicate.skip_binders() {
|
||||
if projection.ty.references_error() {
|
||||
// No point on adding these obligations since there's a type error involved.
|
||||
@ -1162,14 +1163,14 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
self.obligations.reserve(bounds.predicates.len());
|
||||
for predicate in bounds.predicates {
|
||||
self.obligations.reserve(bounds.len());
|
||||
for predicate in bounds {
|
||||
// Change the predicate to refer to the type variable,
|
||||
// which will be the concrete type instead of the opaque type.
|
||||
// This also instantiates nested instances of `impl Trait`.
|
||||
let predicate = self.instantiate_opaque_types_in_map(&predicate);
|
||||
|
||||
let cause = traits::ObligationCause::new(span, self.body_id, traits::SizedReturnType);
|
||||
let cause = traits::ObligationCause::new(span, self.body_id, traits::MiscObligation);
|
||||
|
||||
// Require that the predicate holds for the concrete type.
|
||||
debug!("instantiate_opaque_types: predicate={:?}", predicate);
|
||||
|
@ -376,7 +376,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
||||
| ty::PredicateAtom::Subtype(_)
|
||||
| ty::PredicateAtom::ConstEvaluatable(..)
|
||||
| ty::PredicateAtom::ConstEquate(..) => {
|
||||
let (pred, _) = infcx.replace_bound_vars_with_placeholders(binder);
|
||||
let pred = infcx.replace_bound_vars_with_placeholders(binder);
|
||||
ProcessResult::Changed(mk_pending(vec![
|
||||
obligation.with(pred.to_predicate(self.selcx.tcx())),
|
||||
]))
|
||||
@ -449,6 +449,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
||||
self.selcx.infcx(),
|
||||
obligation.param_env,
|
||||
obligation.cause.body_id,
|
||||
obligation.recursion_depth + 1,
|
||||
arg,
|
||||
obligation.cause.span,
|
||||
) {
|
||||
@ -672,7 +673,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
||||
Ok(Ok(None)) => {
|
||||
*stalled_on = trait_ref_infer_vars(
|
||||
self.selcx,
|
||||
project_obligation.predicate.to_poly_trait_ref(self.selcx.tcx()),
|
||||
project_obligation.predicate.to_poly_trait_ref(tcx),
|
||||
);
|
||||
ProcessResult::Unchanged
|
||||
}
|
||||
|
@ -160,6 +160,10 @@ fn object_safety_violations_for_trait(
|
||||
if !spans.is_empty() {
|
||||
violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
|
||||
}
|
||||
let spans = bounds_reference_self(tcx, trait_def_id);
|
||||
if !spans.is_empty() {
|
||||
violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
|
||||
}
|
||||
|
||||
violations.extend(
|
||||
tcx.associated_items(trait_def_id)
|
||||
@ -239,51 +243,70 @@ fn predicates_reference_self(
|
||||
} else {
|
||||
tcx.predicates_of(trait_def_id)
|
||||
};
|
||||
let self_ty = tcx.types.self_param;
|
||||
let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into());
|
||||
predicates
|
||||
.predicates
|
||||
.iter()
|
||||
.map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp))
|
||||
.filter_map(|(predicate, &sp)| {
|
||||
match predicate.skip_binders() {
|
||||
ty::PredicateAtom::Trait(ref data, _) => {
|
||||
// In the case of a trait predicate, we can skip the "self" type.
|
||||
if data.trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
|
||||
}
|
||||
ty::PredicateAtom::Projection(ref data) => {
|
||||
// And similarly for projections. This should be redundant with
|
||||
// the previous check because any projection should have a
|
||||
// matching `Trait` predicate with the same inputs, but we do
|
||||
// the check to be safe.
|
||||
//
|
||||
// Note that we *do* allow projection *outputs* to contain
|
||||
// `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
|
||||
// we just require the user to specify *both* outputs
|
||||
// in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
|
||||
//
|
||||
// This is ALT2 in issue #56288, see that for discussion of the
|
||||
// possible alternatives.
|
||||
if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) {
|
||||
Some(sp)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
ty::PredicateAtom::WellFormed(..)
|
||||
| ty::PredicateAtom::ObjectSafe(..)
|
||||
| ty::PredicateAtom::TypeOutlives(..)
|
||||
| ty::PredicateAtom::RegionOutlives(..)
|
||||
| ty::PredicateAtom::ClosureKind(..)
|
||||
| ty::PredicateAtom::Subtype(..)
|
||||
| ty::PredicateAtom::ConstEvaluatable(..)
|
||||
| ty::PredicateAtom::ConstEquate(..)
|
||||
| ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
|
||||
}
|
||||
})
|
||||
.map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), *sp))
|
||||
.filter_map(|predicate| predicate_references_self(tcx, predicate))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
|
||||
let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
|
||||
tcx.associated_items(trait_def_id)
|
||||
.in_definition_order()
|
||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
||||
.flat_map(|item| tcx.explicit_item_bounds(item.def_id))
|
||||
.map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), *sp))
|
||||
.filter_map(|predicate| predicate_references_self(tcx, predicate))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn predicate_references_self(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
(predicate, sp): (ty::Predicate<'tcx>, Span),
|
||||
) -> Option<Span> {
|
||||
let self_ty = tcx.types.self_param;
|
||||
let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into());
|
||||
match predicate.skip_binders() {
|
||||
ty::PredicateAtom::Trait(ref data, _) => {
|
||||
// In the case of a trait predicate, we can skip the "self" type.
|
||||
if data.trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
|
||||
}
|
||||
ty::PredicateAtom::Projection(ref data) => {
|
||||
// And similarly for projections. This should be redundant with
|
||||
// the previous check because any projection should have a
|
||||
// matching `Trait` predicate with the same inputs, but we do
|
||||
// the check to be safe.
|
||||
//
|
||||
// It's also won't be redundant if we allow type-generic associated
|
||||
// types for trait objects.
|
||||
//
|
||||
// Note that we *do* allow projection *outputs* to contain
|
||||
// `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
|
||||
// we just require the user to specify *both* outputs
|
||||
// in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
|
||||
//
|
||||
// This is ALT2 in issue #56288, see that for discussion of the
|
||||
// possible alternatives.
|
||||
if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) {
|
||||
Some(sp)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
ty::PredicateAtom::WellFormed(..)
|
||||
| ty::PredicateAtom::ObjectSafe(..)
|
||||
| ty::PredicateAtom::TypeOutlives(..)
|
||||
| ty::PredicateAtom::RegionOutlives(..)
|
||||
| ty::PredicateAtom::ClosureKind(..)
|
||||
| ty::PredicateAtom::Subtype(..)
|
||||
| ty::PredicateAtom::ConstEvaluatable(..)
|
||||
| ty::PredicateAtom::ConstEquate(..)
|
||||
| ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
|
||||
generics_require_sized_self(tcx, trait_def_id)
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
//! Code for projecting associated types out of trait references.
|
||||
|
||||
use super::elaborate_predicates;
|
||||
use super::specialization_graph;
|
||||
use super::translate_substs;
|
||||
use super::util;
|
||||
@ -29,7 +28,6 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
||||
use rustc_middle::ty::subst::Subst;
|
||||
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
pub use rustc_middle::traits::Reveal;
|
||||
|
||||
@ -53,13 +51,16 @@ pub enum ProjectionTyError<'tcx> {
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
enum ProjectionTyCandidate<'tcx> {
|
||||
// from a where-clause in the env or object type
|
||||
/// From a where-clause in the env or object type
|
||||
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
|
||||
|
||||
// from the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C
|
||||
/// From the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C
|
||||
TraitDef(ty::PolyProjectionPredicate<'tcx>),
|
||||
|
||||
// from a "impl" (or a "pseudo-impl" returned by select)
|
||||
/// Bounds specified on an object type
|
||||
Object(ty::PolyProjectionPredicate<'tcx>),
|
||||
|
||||
/// From a "impl" (or a "pseudo-impl" returned by select)
|
||||
Select(Selection<'tcx>),
|
||||
}
|
||||
|
||||
@ -167,7 +168,7 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
|
||||
|
||||
let infcx = selcx.infcx();
|
||||
infcx.commit_if_ok(|_snapshot| {
|
||||
let (placeholder_predicate, _) =
|
||||
let placeholder_predicate =
|
||||
infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
|
||||
|
||||
let placeholder_obligation = obligation.with(placeholder_predicate);
|
||||
@ -561,14 +562,6 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
|
||||
} else {
|
||||
obligations.extend(ty.obligations);
|
||||
}
|
||||
|
||||
obligations.push(get_paranoid_cache_value_obligation(
|
||||
infcx,
|
||||
param_env,
|
||||
projection_ty,
|
||||
cause,
|
||||
depth,
|
||||
));
|
||||
return Ok(Some(ty.value));
|
||||
}
|
||||
Err(ProjectionCacheEntry::Error) => {
|
||||
@ -703,45 +696,6 @@ fn prune_cache_value_obligations<'a, 'tcx>(
|
||||
NormalizedTy { value: result.value, obligations }
|
||||
}
|
||||
|
||||
/// Whenever we give back a cache result for a projection like `<T as
|
||||
/// Trait>::Item ==> X`, we *always* include the obligation to prove
|
||||
/// that `T: Trait` (we may also include some other obligations). This
|
||||
/// may or may not be necessary -- in principle, all the obligations
|
||||
/// that must be proven to show that `T: Trait` were also returned
|
||||
/// when the cache was first populated. But there are some vague concerns,
|
||||
/// and so we take the precautionary measure of including `T: Trait` in
|
||||
/// the result:
|
||||
///
|
||||
/// Concern #1. The current setup is fragile. Perhaps someone could
|
||||
/// have failed to prove the concerns from when the cache was
|
||||
/// populated, but also not have used a snapshot, in which case the
|
||||
/// cache could remain populated even though `T: Trait` has not been
|
||||
/// shown. In this case, the "other code" is at fault -- when you
|
||||
/// project something, you are supposed to either have a snapshot or
|
||||
/// else prove all the resulting obligations -- but it's still easy to
|
||||
/// get wrong.
|
||||
///
|
||||
/// Concern #2. Even within the snapshot, if those original
|
||||
/// obligations are not yet proven, then we are able to do projections
|
||||
/// that may yet turn out to be wrong. This *may* lead to some sort
|
||||
/// of trouble, though we don't have a concrete example of how that
|
||||
/// can occur yet. But it seems risky at best.
|
||||
fn get_paranoid_cache_value_obligation<'a, 'tcx>(
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
depth: usize,
|
||||
) -> PredicateObligation<'tcx> {
|
||||
let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref();
|
||||
Obligation {
|
||||
cause,
|
||||
recursion_depth: depth,
|
||||
param_env,
|
||||
predicate: trait_ref.without_const().to_predicate(infcx.tcx),
|
||||
}
|
||||
}
|
||||
|
||||
/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
|
||||
/// hold. In various error cases, we cannot generate a valid
|
||||
/// normalized projection. Therefore, we create an inference variable
|
||||
@ -848,12 +802,21 @@ fn project_type<'cx, 'tcx>(
|
||||
|
||||
assemble_candidates_from_trait_def(selcx, obligation, &obligation_trait_ref, &mut candidates);
|
||||
|
||||
assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates);
|
||||
assemble_candidates_from_object_ty(selcx, obligation, &obligation_trait_ref, &mut candidates);
|
||||
|
||||
if let ProjectionTyCandidateSet::Single(ProjectionTyCandidate::Object(_)) = candidates {
|
||||
// Avoid normalization cycle from selection (see
|
||||
// `assemble_candidates_from_object_ty`).
|
||||
// FIXME(lazy_normalization): Lazy normalization should save us from
|
||||
// having to do special case this.
|
||||
} else {
|
||||
assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates);
|
||||
};
|
||||
|
||||
match candidates {
|
||||
ProjectionTyCandidateSet::Single(candidate) => Ok(ProjectedTy::Progress(
|
||||
confirm_candidate(selcx, obligation, &obligation_trait_ref, candidate),
|
||||
)),
|
||||
ProjectionTyCandidateSet::Single(candidate) => {
|
||||
Ok(ProjectedTy::Progress(confirm_candidate(selcx, obligation, candidate)))
|
||||
}
|
||||
ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress(
|
||||
selcx
|
||||
.tcx()
|
||||
@ -884,6 +847,7 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>(
|
||||
candidate_set,
|
||||
ProjectionTyCandidate::ParamEnv,
|
||||
obligation.param_env.caller_bounds().iter(),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
@ -909,10 +873,8 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
|
||||
// Check whether the self-type is itself a projection.
|
||||
// If so, extract what we know from the trait and try to come up with a good answer.
|
||||
let bounds = match *obligation_trait_ref.self_ty().kind() {
|
||||
ty::Projection(ref data) => {
|
||||
tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs)
|
||||
}
|
||||
ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs),
|
||||
ty::Projection(ref data) => tcx.item_bounds(data.item_def_id).subst(tcx, data.substs),
|
||||
ty::Opaque(def_id, substs) => tcx.item_bounds(def_id).subst(tcx, substs),
|
||||
ty::Infer(ty::TyVar(_)) => {
|
||||
// If the self-type is an inference variable, then it MAY wind up
|
||||
// being a projected type, so induce an ambiguity.
|
||||
@ -929,9 +891,57 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
|
||||
candidate_set,
|
||||
ProjectionTyCandidate::TraitDef,
|
||||
bounds.iter(),
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
/// In the case of a trait object like
|
||||
/// `<dyn Iterator<Item = ()> as Iterator>::Item` we can use the existential
|
||||
/// predicate in the trait object.
|
||||
///
|
||||
/// We don't go through the select candidate for these bounds to avoid cycles:
|
||||
/// In the above case, `dyn Iterator<Item = ()>: Iterator` would create a
|
||||
/// nested obligation of `<dyn Iterator<Item = ()> as Iterator>::Item: Sized`,
|
||||
/// this then has to be normalized without having to prove
|
||||
/// `dyn Iterator<Item = ()>: Iterator` again.
|
||||
fn assemble_candidates_from_object_ty<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
||||
) {
|
||||
debug!("assemble_candidates_from_object_ty(..)");
|
||||
|
||||
let tcx = selcx.tcx();
|
||||
|
||||
let self_ty = obligation_trait_ref.self_ty();
|
||||
let object_ty = selcx.infcx().shallow_resolve(self_ty);
|
||||
let data = match object_ty.kind() {
|
||||
ty::Dynamic(data, ..) => data,
|
||||
ty::Infer(ty::TyVar(_)) => {
|
||||
// If the self-type is an inference variable, then it MAY wind up
|
||||
// being an object type, so induce an ambiguity.
|
||||
candidate_set.mark_ambiguous();
|
||||
return;
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
let env_predicates = data
|
||||
.projection_bounds()
|
||||
.filter(|bound| bound.item_def_id() == obligation.predicate.item_def_id)
|
||||
.map(|p| p.with_self_ty(tcx, object_ty).to_predicate(tcx));
|
||||
|
||||
assemble_candidates_from_predicates(
|
||||
selcx,
|
||||
obligation,
|
||||
obligation_trait_ref,
|
||||
candidate_set,
|
||||
ProjectionTyCandidate::Object,
|
||||
env_predicates,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
fn assemble_candidates_from_predicates<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
@ -939,6 +949,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
|
||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
||||
ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
|
||||
env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
|
||||
potentially_unnormalized_candidates: bool,
|
||||
) {
|
||||
debug!("assemble_candidates_from_predicates(obligation={:?})", obligation);
|
||||
let infcx = selcx.infcx();
|
||||
@ -950,16 +961,12 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
|
||||
|
||||
let is_match = same_def_id
|
||||
&& infcx.probe(|_| {
|
||||
let data_poly_trait_ref = data.to_poly_trait_ref(infcx.tcx);
|
||||
let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
|
||||
infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(obligation_poly_trait_ref, data_poly_trait_ref)
|
||||
.map(|InferOk { obligations: _, value: () }| {
|
||||
// FIXME(#32730) -- do we need to take obligations
|
||||
// into account in any way? At the moment, no.
|
||||
})
|
||||
.is_ok()
|
||||
selcx.match_projection_projections(
|
||||
obligation,
|
||||
obligation_trait_ref,
|
||||
&data,
|
||||
potentially_unnormalized_candidates,
|
||||
)
|
||||
});
|
||||
|
||||
debug!(
|
||||
@ -970,6 +977,15 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
|
||||
|
||||
if is_match {
|
||||
candidate_set.push_candidate(ctor(data));
|
||||
|
||||
if potentially_unnormalized_candidates
|
||||
&& !obligation.predicate.has_infer_types_or_consts()
|
||||
{
|
||||
// HACK: Pick the first trait def candidate for a fully
|
||||
// inferred predicate. This is to allow duplicates that
|
||||
// differ only in normalization.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1003,7 +1019,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||
super::ImplSource::Closure(_)
|
||||
| super::ImplSource::Generator(_)
|
||||
| super::ImplSource::FnPointer(_)
|
||||
| super::ImplSource::Object(_)
|
||||
| super::ImplSource::TraitAlias(_) => {
|
||||
debug!("assemble_candidates_from_impls: impl_source={:?}", impl_source);
|
||||
true
|
||||
@ -1128,6 +1143,12 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||
// in `assemble_candidates_from_param_env`.
|
||||
false
|
||||
}
|
||||
super::ImplSource::Object(_) => {
|
||||
// Handled by the `Object` projection candidate. See
|
||||
// `assemble_candidates_from_object_ty` for an explanation of
|
||||
// why we special case object types.
|
||||
false
|
||||
}
|
||||
super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) => {
|
||||
// These traits have no associated types.
|
||||
selcx.tcx().sess.delay_span_bug(
|
||||
@ -1153,19 +1174,22 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||
fn confirm_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
||||
candidate: ProjectionTyCandidate<'tcx>,
|
||||
) -> Progress<'tcx> {
|
||||
debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation);
|
||||
|
||||
let mut progress = match candidate {
|
||||
ProjectionTyCandidate::ParamEnv(poly_projection)
|
||||
| ProjectionTyCandidate::TraitDef(poly_projection) => {
|
||||
confirm_param_env_candidate(selcx, obligation, poly_projection)
|
||||
| ProjectionTyCandidate::Object(poly_projection) => {
|
||||
confirm_param_env_candidate(selcx, obligation, poly_projection, false)
|
||||
}
|
||||
|
||||
ProjectionTyCandidate::TraitDef(poly_projection) => {
|
||||
confirm_param_env_candidate(selcx, obligation, poly_projection, true)
|
||||
}
|
||||
|
||||
ProjectionTyCandidate::Select(impl_source) => {
|
||||
confirm_select_candidate(selcx, obligation, obligation_trait_ref, impl_source)
|
||||
confirm_select_candidate(selcx, obligation, impl_source)
|
||||
}
|
||||
};
|
||||
// When checking for cycle during evaluation, we compare predicates with
|
||||
@ -1182,7 +1206,6 @@ fn confirm_candidate<'cx, 'tcx>(
|
||||
fn confirm_select_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
||||
impl_source: Selection<'tcx>,
|
||||
) -> Progress<'tcx> {
|
||||
match impl_source {
|
||||
@ -1193,10 +1216,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
|
||||
super::ImplSource::DiscriminantKind(data) => {
|
||||
confirm_discriminant_kind_candidate(selcx, obligation, data)
|
||||
}
|
||||
super::ImplSource::Object(_) => {
|
||||
confirm_object_candidate(selcx, obligation, obligation_trait_ref)
|
||||
}
|
||||
super::ImplSource::AutoImpl(..)
|
||||
super::ImplSource::Object(_)
|
||||
| super::ImplSource::AutoImpl(..)
|
||||
| super::ImplSource::Param(..)
|
||||
| super::ImplSource::Builtin(..)
|
||||
| super::ImplSource::TraitAlias(..) =>
|
||||
@ -1211,72 +1232,6 @@ fn confirm_select_candidate<'cx, 'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn confirm_object_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
||||
) -> Progress<'tcx> {
|
||||
let self_ty = obligation_trait_ref.self_ty();
|
||||
let object_ty = selcx.infcx().shallow_resolve(self_ty);
|
||||
debug!("confirm_object_candidate(object_ty={:?})", object_ty);
|
||||
let data = match object_ty.kind() {
|
||||
ty::Dynamic(data, ..) => data,
|
||||
_ => span_bug!(
|
||||
obligation.cause.span,
|
||||
"confirm_object_candidate called with non-object: {:?}",
|
||||
object_ty
|
||||
),
|
||||
};
|
||||
let env_predicates = data
|
||||
.projection_bounds()
|
||||
.map(|p| p.with_self_ty(selcx.tcx(), object_ty).to_predicate(selcx.tcx()));
|
||||
let env_predicate = {
|
||||
let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates);
|
||||
|
||||
// select only those projections that are actually projecting an
|
||||
// item with the correct name
|
||||
|
||||
let env_predicates = env_predicates.filter_map(|o| match o.predicate.skip_binders() {
|
||||
ty::PredicateAtom::Projection(data)
|
||||
if data.projection_ty.item_def_id == obligation.predicate.item_def_id =>
|
||||
{
|
||||
Some(ty::Binder::bind(data))
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
|
||||
// select those with a relevant trait-ref
|
||||
let mut env_predicates = env_predicates.filter(|data| {
|
||||
let data_poly_trait_ref = data.to_poly_trait_ref(selcx.tcx());
|
||||
let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
|
||||
selcx.infcx().probe(|_| {
|
||||
selcx
|
||||
.infcx()
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(obligation_poly_trait_ref, data_poly_trait_ref)
|
||||
.is_ok()
|
||||
})
|
||||
});
|
||||
|
||||
// select the first matching one; there really ought to be one or
|
||||
// else the object type is not WF, since an object type should
|
||||
// include all of its projections explicitly
|
||||
match env_predicates.next() {
|
||||
Some(env_predicate) => env_predicate,
|
||||
None => {
|
||||
debug!(
|
||||
"confirm_object_candidate: no env-predicate \
|
||||
found in object type `{:?}`; ill-formed",
|
||||
object_ty
|
||||
);
|
||||
return Progress::error(selcx.tcx());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
confirm_param_env_candidate(selcx, obligation, env_predicate)
|
||||
}
|
||||
|
||||
fn confirm_generator_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
@ -1325,7 +1280,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
|
||||
}
|
||||
});
|
||||
|
||||
confirm_param_env_candidate(selcx, obligation, predicate)
|
||||
confirm_param_env_candidate(selcx, obligation, predicate, false)
|
||||
.with_addl_obligations(impl_source.nested)
|
||||
.with_addl_obligations(obligations)
|
||||
}
|
||||
@ -1347,7 +1302,7 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
|
||||
ty: self_ty.discriminant_ty(tcx),
|
||||
};
|
||||
|
||||
confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate))
|
||||
confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate), false)
|
||||
}
|
||||
|
||||
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
|
||||
@ -1422,13 +1377,14 @@ fn confirm_callable_candidate<'cx, 'tcx>(
|
||||
ty: ret_type,
|
||||
});
|
||||
|
||||
confirm_param_env_candidate(selcx, obligation, predicate)
|
||||
confirm_param_env_candidate(selcx, obligation, predicate, false)
|
||||
}
|
||||
|
||||
fn confirm_param_env_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
poly_cache_entry: ty::PolyProjectionPredicate<'tcx>,
|
||||
potentially_unnormalized_candidate: bool,
|
||||
) -> Progress<'tcx> {
|
||||
let infcx = selcx.infcx();
|
||||
let cause = &obligation.cause;
|
||||
@ -1442,8 +1398,28 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
|
||||
|
||||
let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx);
|
||||
let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx);
|
||||
let mut nested_obligations = Vec::new();
|
||||
let cache_trait_ref = if potentially_unnormalized_candidate {
|
||||
ensure_sufficient_stack(|| {
|
||||
normalize_with_depth_to(
|
||||
selcx,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
&cache_trait_ref,
|
||||
&mut nested_obligations,
|
||||
)
|
||||
})
|
||||
} else {
|
||||
cache_trait_ref
|
||||
};
|
||||
|
||||
match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) {
|
||||
Ok(InferOk { value: _, obligations }) => Progress { ty: cache_entry.ty, obligations },
|
||||
Ok(InferOk { value: _, obligations }) => {
|
||||
nested_obligations.extend(obligations);
|
||||
assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
|
||||
Progress { ty: cache_entry.ty, obligations: nested_obligations }
|
||||
}
|
||||
Err(e) => {
|
||||
let msg = format!(
|
||||
"Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}",
|
||||
@ -1463,7 +1439,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
||||
) -> Progress<'tcx> {
|
||||
let tcx = selcx.tcx();
|
||||
|
||||
let ImplSourceUserDefinedData { impl_def_id, substs, nested } = impl_impl_source;
|
||||
let ImplSourceUserDefinedData { impl_def_id, substs, mut nested } = impl_impl_source;
|
||||
let assoc_item_id = obligation.predicate.item_def_id;
|
||||
let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
|
||||
|
||||
@ -1496,15 +1472,48 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
||||
let ty = tcx.type_of(assoc_ty.item.def_id);
|
||||
if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() {
|
||||
let err = tcx.ty_error_with_message(
|
||||
DUMMY_SP,
|
||||
obligation.cause.span,
|
||||
"impl item and trait item have different parameter counts",
|
||||
);
|
||||
Progress { ty: err, obligations: nested }
|
||||
} else {
|
||||
assoc_ty_own_obligations(selcx, obligation, &mut nested);
|
||||
Progress { ty: ty.subst(tcx, substs), obligations: nested }
|
||||
}
|
||||
}
|
||||
|
||||
// Get obligations corresponding to the predicates from the where-clause of the
|
||||
// associated type itself.
|
||||
// Note: `feature(generic_associated_types)` is required to write such
|
||||
// predicates, even for non-generic associcated types.
|
||||
fn assoc_ty_own_obligations<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
nested: &mut Vec<PredicateObligation<'tcx>>,
|
||||
) {
|
||||
let tcx = selcx.tcx();
|
||||
for predicate in tcx
|
||||
.predicates_of(obligation.predicate.item_def_id)
|
||||
.instantiate_own(tcx, obligation.predicate.substs)
|
||||
.predicates
|
||||
{
|
||||
let normalized = normalize_with_depth_to(
|
||||
selcx,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
&predicate,
|
||||
nested,
|
||||
);
|
||||
nested.push(Obligation::with_depth(
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
obligation.param_env,
|
||||
normalized,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// Locate the definition of an associated type in the specialization hierarchy,
|
||||
/// starting from the given impl.
|
||||
///
|
||||
|
@ -165,7 +165,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates);
|
||||
|
||||
let needs_infer = stack.obligation.predicate.needs_infer();
|
||||
let needs_infer = stack.obligation.predicate.has_infer_types_or_consts();
|
||||
|
||||
// If there are STILL multiple candidates, we can further
|
||||
// reduce the list by dropping duplicates -- including
|
||||
@ -327,8 +327,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
.infcx
|
||||
.probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
|
||||
|
||||
if result {
|
||||
candidates.vec.push(ProjectionCandidate);
|
||||
for predicate_index in result {
|
||||
candidates.vec.push(ProjectionCandidate(predicate_index));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,12 +10,13 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::bit_set::GrowableBitSet;
|
||||
use rustc_infer::infer::InferOk;
|
||||
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::{ToPolyTraitRef, ToPredicate, WithConstness};
|
||||
use rustc_span::def_id::DefId;
|
||||
|
||||
use crate::traits::project::{self, normalize_with_depth};
|
||||
use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
|
||||
use crate::traits::select::TraitObligationExt;
|
||||
use crate::traits::util;
|
||||
use crate::traits::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
|
||||
@ -68,9 +69,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
Ok(ImplSource::AutoImpl(data))
|
||||
}
|
||||
|
||||
ProjectionCandidate => {
|
||||
self.confirm_projection_candidate(obligation);
|
||||
Ok(ImplSource::Param(Vec::new()))
|
||||
ProjectionCandidate(idx) => {
|
||||
let obligations = self.confirm_projection_candidate(obligation, idx);
|
||||
Ok(ImplSource::Param(obligations))
|
||||
}
|
||||
|
||||
ClosureCandidate => {
|
||||
@ -116,10 +117,72 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) {
|
||||
fn confirm_projection_candidate(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
idx: usize,
|
||||
) -> Vec<PredicateObligation<'tcx>> {
|
||||
self.infcx.commit_unconditionally(|_| {
|
||||
let result = self.match_projection_obligation_against_definition_bounds(obligation);
|
||||
assert!(result);
|
||||
let tcx = self.tcx();
|
||||
|
||||
let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
|
||||
let placeholder_trait_predicate =
|
||||
self.infcx().replace_bound_vars_with_placeholders(&trait_predicate);
|
||||
let placeholder_self_ty = placeholder_trait_predicate.self_ty();
|
||||
let (def_id, substs) = match *placeholder_self_ty.kind() {
|
||||
ty::Projection(proj) => (proj.item_def_id, proj.substs),
|
||||
ty::Opaque(def_id, substs) => (def_id, substs),
|
||||
_ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty),
|
||||
};
|
||||
|
||||
let candidate_predicate = tcx.item_bounds(def_id)[idx].subst(tcx, substs);
|
||||
let candidate = candidate_predicate
|
||||
.to_opt_poly_trait_ref()
|
||||
.expect("projection candidate is not a trait predicate");
|
||||
let mut obligations = Vec::new();
|
||||
let candidate = normalize_with_depth_to(
|
||||
self,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
&candidate,
|
||||
&mut obligations,
|
||||
);
|
||||
|
||||
obligations.extend(
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(placeholder_trait_predicate.trait_ref.to_poly_trait_ref(), candidate)
|
||||
.map(|InferOk { obligations, .. }| obligations)
|
||||
.unwrap_or_else(|_| {
|
||||
bug!(
|
||||
"Projection bound `{:?}` was applicable to `{:?}` but now is not",
|
||||
candidate,
|
||||
obligation
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
if let ty::Projection(..) = placeholder_self_ty.kind() {
|
||||
for predicate in tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates {
|
||||
let normalized = normalize_with_depth_to(
|
||||
self,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
&predicate,
|
||||
&mut obligations,
|
||||
);
|
||||
obligations.push(Obligation::with_depth(
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
obligation.param_env,
|
||||
normalized,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
obligations
|
||||
})
|
||||
}
|
||||
|
||||
@ -229,7 +292,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
let trait_obligations: Vec<PredicateObligation<'_>> =
|
||||
self.infcx.commit_unconditionally(|_| {
|
||||
let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
|
||||
let (trait_ref, _) =
|
||||
let trait_ref =
|
||||
self.infcx.replace_bound_vars_with_placeholders(&poly_trait_ref);
|
||||
let cause = obligation.derived_cause(ImplDerivedObligation);
|
||||
self.impl_or_trait_obligations(
|
||||
@ -307,55 +370,70 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// relying on projections in the impl-trait-ref.
|
||||
//
|
||||
// e.g., `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V`
|
||||
impl_obligations.append(&mut substs.obligations);
|
||||
substs.obligations.append(&mut impl_obligations);
|
||||
|
||||
ImplSourceUserDefinedData { impl_def_id, substs: substs.value, nested: impl_obligations }
|
||||
ImplSourceUserDefinedData { impl_def_id, substs: substs.value, nested: substs.obligations }
|
||||
}
|
||||
|
||||
fn confirm_object_candidate(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
) -> ImplSourceObjectData<'tcx, PredicateObligation<'tcx>> {
|
||||
let tcx = self.tcx();
|
||||
debug!("confirm_object_candidate({:?})", obligation);
|
||||
|
||||
// FIXME(nmatsakis) skipping binder here seems wrong -- we should
|
||||
// probably flatten the binder from the obligation and the binder
|
||||
// from the object. Have to try to make a broken test case that
|
||||
// results.
|
||||
let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
|
||||
let poly_trait_ref = match self_ty.kind() {
|
||||
ty::Dynamic(data, ..) => data
|
||||
.principal()
|
||||
.unwrap_or_else(|| {
|
||||
span_bug!(obligation.cause.span, "object candidate with no principal")
|
||||
})
|
||||
.with_self_ty(self.tcx(), self_ty),
|
||||
let trait_predicate =
|
||||
self.infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
|
||||
let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty());
|
||||
let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref);
|
||||
let data = match self_ty.kind() {
|
||||
ty::Dynamic(data, ..) => {
|
||||
self.infcx
|
||||
.replace_bound_vars_with_fresh_vars(
|
||||
obligation.cause.span,
|
||||
HigherRankedType,
|
||||
data,
|
||||
)
|
||||
.0
|
||||
}
|
||||
_ => span_bug!(obligation.cause.span, "object candidate with non-object"),
|
||||
};
|
||||
|
||||
let object_trait_ref = data
|
||||
.principal()
|
||||
.unwrap_or_else(|| {
|
||||
span_bug!(obligation.cause.span, "object candidate with no principal")
|
||||
})
|
||||
.with_self_ty(self.tcx(), self_ty);
|
||||
|
||||
let mut upcast_trait_ref = None;
|
||||
let mut nested = vec![];
|
||||
let vtable_base;
|
||||
|
||||
{
|
||||
let tcx = self.tcx();
|
||||
|
||||
// We want to find the first supertrait in the list of
|
||||
// supertraits that we can unify with, and do that
|
||||
// unification. We know that there is exactly one in the list
|
||||
// where we can unify, because otherwise select would have
|
||||
// reported an ambiguity. (When we do find a match, also
|
||||
// record it for later.)
|
||||
let nonmatching = util::supertraits(tcx, poly_trait_ref).take_while(|&t| {
|
||||
match self.infcx.commit_if_ok(|_| self.match_poly_trait_ref(obligation, t)) {
|
||||
Ok(obligations) => {
|
||||
upcast_trait_ref = Some(t);
|
||||
nested.extend(obligations);
|
||||
false
|
||||
let nonmatching = util::supertraits(tcx, ty::Binder::dummy(object_trait_ref))
|
||||
.take_while(|&t| {
|
||||
match self.infcx.commit_if_ok(|_| {
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(obligation_trait_ref, t)
|
||||
.map(|InferOk { obligations, .. }| obligations)
|
||||
.map_err(|_| ())
|
||||
}) {
|
||||
Ok(obligations) => {
|
||||
upcast_trait_ref = Some(t);
|
||||
nested.extend(obligations);
|
||||
false
|
||||
}
|
||||
Err(_) => true,
|
||||
}
|
||||
Err(_) => true,
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Additionally, for each of the non-matching predicates that
|
||||
// we pass over, we sum up the set of number of vtable
|
||||
@ -364,7 +442,73 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum();
|
||||
}
|
||||
|
||||
ImplSourceObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested }
|
||||
let upcast_trait_ref = upcast_trait_ref.unwrap();
|
||||
|
||||
// Check supertraits hold. This is so that their associated type bounds
|
||||
// will be checked in the code below.
|
||||
for super_trait in tcx
|
||||
.super_predicates_of(trait_predicate.def_id())
|
||||
.instantiate(tcx, trait_predicate.trait_ref.substs)
|
||||
.predicates
|
||||
.into_iter()
|
||||
{
|
||||
if let ty::PredicateAtom::Trait(..) = super_trait.skip_binders() {
|
||||
let normalized_super_trait = normalize_with_depth_to(
|
||||
self,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
&super_trait,
|
||||
&mut nested,
|
||||
);
|
||||
nested.push(Obligation::new(
|
||||
obligation.cause.clone(),
|
||||
obligation.param_env.clone(),
|
||||
normalized_super_trait,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let assoc_types: Vec<_> = tcx
|
||||
.associated_items(trait_predicate.def_id())
|
||||
.in_definition_order()
|
||||
.filter_map(
|
||||
|item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None },
|
||||
)
|
||||
.collect();
|
||||
|
||||
for assoc_type in assoc_types {
|
||||
if !tcx.generics_of(assoc_type).params.is_empty() {
|
||||
// FIXME(generic_associated_types) generate placeholders to
|
||||
// extend the trait substs.
|
||||
tcx.sess.span_fatal(
|
||||
obligation.cause.span,
|
||||
"generic associated types in trait objects are not supported yet",
|
||||
);
|
||||
}
|
||||
// This maybe belongs in wf, but that can't (doesn't) handle
|
||||
// higher-ranked things.
|
||||
// Prevent, e.g., `dyn Iterator<Item = str>`.
|
||||
for bound in self.tcx().item_bounds(assoc_type) {
|
||||
let subst_bound = bound.subst(tcx, trait_predicate.trait_ref.substs);
|
||||
let normalized_bound = normalize_with_depth_to(
|
||||
self,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
&subst_bound,
|
||||
&mut nested,
|
||||
);
|
||||
nested.push(Obligation::new(
|
||||
obligation.cause.clone(),
|
||||
obligation.param_env.clone(),
|
||||
normalized_bound,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
debug!("confirm_object_candidate: nested: {:?}", nested);
|
||||
ImplSourceObjectData { upcast_trait_ref, vtable_base, nested }
|
||||
}
|
||||
|
||||
fn confirm_fn_pointer_candidate(
|
||||
@ -386,8 +530,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
)
|
||||
.map_bound(|(trait_ref, _)| trait_ref);
|
||||
|
||||
let Normalized { value: trait_ref, obligations } = ensure_sufficient_stack(|| {
|
||||
project::normalize_with_depth(
|
||||
let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| {
|
||||
normalize_with_depth(
|
||||
self,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
@ -396,12 +540,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
)
|
||||
});
|
||||
|
||||
self.confirm_poly_trait_refs(
|
||||
obligations.extend(self.confirm_poly_trait_refs(
|
||||
obligation.cause.clone(),
|
||||
obligation.param_env,
|
||||
obligation.predicate.to_poly_trait_ref(),
|
||||
trait_ref,
|
||||
)?;
|
||||
)?);
|
||||
Ok(ImplSourceFnPointerData { fn_ty: self_ty, nested: obligations })
|
||||
}
|
||||
|
||||
@ -413,7 +557,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
debug!("confirm_trait_alias_candidate({:?}, {:?})", obligation, alias_def_id);
|
||||
|
||||
self.infcx.commit_unconditionally(|_| {
|
||||
let (predicate, _) =
|
||||
let predicate =
|
||||
self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
|
||||
let trait_ref = predicate.trait_ref;
|
||||
let trait_def_id = trait_ref.def_id;
|
||||
|
@ -9,6 +9,7 @@ use super::coherence::{self, Conflict};
|
||||
use super::const_evaluatable;
|
||||
use super::project;
|
||||
use super::project::normalize_with_depth_to;
|
||||
use super::project::ProjectionTyObligation;
|
||||
use super::util;
|
||||
use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
|
||||
use super::wf;
|
||||
@ -36,9 +37,8 @@ use rustc_middle::ty::fast_reject;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
|
||||
use rustc_middle::ty::{
|
||||
self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
|
||||
};
|
||||
use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
|
||||
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, WithConstness};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
@ -343,7 +343,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
Err(SelectionError::Overflow)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
Ok(candidate) => Ok(Some(candidate)),
|
||||
Ok(candidate) => {
|
||||
debug!("select: candidate = {:?}", candidate);
|
||||
Ok(Some(candidate))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -413,9 +416,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
predicates: I,
|
||||
) -> Result<EvaluationResult, OverflowError>
|
||||
where
|
||||
I: IntoIterator<Item = PredicateObligation<'tcx>>,
|
||||
I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
|
||||
{
|
||||
let mut result = EvaluatedToOk;
|
||||
debug!("evaluate_predicates_recursively({:?})", predicates);
|
||||
for obligation in predicates {
|
||||
let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
|
||||
debug!("evaluate_predicate_recursively({:?}) = {:?}", obligation, eval);
|
||||
@ -436,9 +440,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
) -> Result<EvaluationResult, OverflowError> {
|
||||
debug!(
|
||||
"evaluate_predicate_recursively(previous_stack={:?}, obligation={:?})",
|
||||
previous_stack.head(),
|
||||
obligation
|
||||
"evaluate_predicate_recursively(obligation={:?}, previous_stack={:?})",
|
||||
obligation,
|
||||
previous_stack.head()
|
||||
);
|
||||
|
||||
// `previous_stack` stores a `TraitObligation`, while `obligation` is
|
||||
@ -479,15 +483,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
self.infcx,
|
||||
obligation.param_env,
|
||||
obligation.cause.body_id,
|
||||
obligation.recursion_depth + 1,
|
||||
arg,
|
||||
obligation.cause.span,
|
||||
) {
|
||||
Some(mut obligations) => {
|
||||
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
|
||||
self.evaluate_predicates_recursively(
|
||||
previous_stack,
|
||||
obligations.into_iter(),
|
||||
)
|
||||
self.evaluate_predicates_recursively(previous_stack, obligations)
|
||||
}
|
||||
None => Ok(EvaluatedToAmbig),
|
||||
},
|
||||
@ -511,10 +513,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
match project::poly_project_and_unify_type(self, &project_obligation) {
|
||||
Ok(Ok(Some(mut subobligations))) => {
|
||||
self.add_depth(subobligations.iter_mut(), obligation.recursion_depth);
|
||||
let result = self.evaluate_predicates_recursively(
|
||||
previous_stack,
|
||||
subobligations.into_iter(),
|
||||
);
|
||||
let result = self
|
||||
.evaluate_predicates_recursively(previous_stack, subobligations);
|
||||
if let Some(key) =
|
||||
ProjectionCacheKey::from_poly_projection_predicate(self, data)
|
||||
{
|
||||
@ -879,10 +879,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
let result = self.evaluation_probe(|this| {
|
||||
let candidate = (*candidate).clone();
|
||||
match this.confirm_candidate(stack.obligation, candidate) {
|
||||
Ok(selection) => this.evaluate_predicates_recursively(
|
||||
stack.list(),
|
||||
selection.nested_obligations().into_iter(),
|
||||
),
|
||||
Ok(selection) => {
|
||||
debug!("evaluate_candidate: selection = {:?}", selection);
|
||||
this.evaluate_predicates_recursively(
|
||||
stack.list(),
|
||||
selection.nested_obligations().into_iter(),
|
||||
)
|
||||
}
|
||||
Err(..) => Ok(EvaluatedToErr),
|
||||
}
|
||||
})?;
|
||||
@ -943,10 +946,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
/// to have a *lower* recursion_depth than the obligation used to create it.
|
||||
/// Projection sub-obligations may be returned from the projection cache,
|
||||
/// which results in obligations with an 'old' `recursion_depth`.
|
||||
/// Additionally, methods like `wf::obligations` and
|
||||
/// `InferCtxt.subtype_predicate` produce subobligations without
|
||||
/// taking in a 'parent' depth, causing the generated subobligations
|
||||
/// to have a `recursion_depth` of `0`.
|
||||
/// Additionally, methods like `InferCtxt.subtype_predicate` produce
|
||||
/// subobligations without taking in a 'parent' depth, causing the
|
||||
/// generated subobligations to have a `recursion_depth` of `0`.
|
||||
///
|
||||
/// To ensure that obligation_depth never decreasees, we force all subobligations
|
||||
/// to have at least the depth of the original obligation.
|
||||
@ -1156,12 +1158,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
self.infcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate);
|
||||
}
|
||||
|
||||
/// Matches a predicate against the bounds of its self type.
|
||||
///
|
||||
/// Given an obligation like `<T as Foo>::Bar: Baz` where the self type is
|
||||
/// a projection, look at the bounds of `T::Bar`, see if we can find a
|
||||
/// `Baz` bound. We return indexes into the list returned by
|
||||
/// `tcx.item_bounds` for any applicable bounds.
|
||||
fn match_projection_obligation_against_definition_bounds(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
) -> bool {
|
||||
) -> smallvec::SmallVec<[usize; 2]> {
|
||||
let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
|
||||
let (placeholder_trait_predicate, _) =
|
||||
let placeholder_trait_predicate =
|
||||
self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate);
|
||||
debug!(
|
||||
"match_projection_obligation_against_definition_bounds: \
|
||||
@ -1170,11 +1178,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
);
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let predicates = match *placeholder_trait_predicate.trait_ref.self_ty().kind() {
|
||||
ty::Projection(ref data) => {
|
||||
tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs)
|
||||
}
|
||||
ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs),
|
||||
let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() {
|
||||
ty::Projection(ref data) => (data.item_def_id, data.substs),
|
||||
ty::Opaque(def_id, substs) => (def_id, substs),
|
||||
_ => {
|
||||
span_bug!(
|
||||
obligation.cause.span,
|
||||
@ -1184,48 +1190,86 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
);
|
||||
}
|
||||
};
|
||||
let bounds = tcx.item_bounds(def_id).subst(tcx, substs);
|
||||
|
||||
let matching_bound = predicates.iter().find_map(|bound| {
|
||||
if let ty::PredicateAtom::Trait(pred, _) = bound.skip_binders() {
|
||||
let bound = ty::Binder::bind(pred.trait_ref);
|
||||
if self.infcx.probe(|_| {
|
||||
self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref)
|
||||
}) {
|
||||
return Some(bound);
|
||||
// The bounds returned by `item_bounds` may contain duplicates after
|
||||
// normalization, so try to deduplicate when possible to avoid
|
||||
// unnecessary ambiguity.
|
||||
let mut distinct_normalized_bounds = FxHashSet::default();
|
||||
|
||||
let matching_bounds = bounds
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(idx, bound)| {
|
||||
if let ty::PredicateAtom::Trait(pred, _) = bound.skip_binders() {
|
||||
let bound = ty::Binder::bind(pred.trait_ref);
|
||||
if self.infcx.probe(|_| {
|
||||
match self.match_projection(
|
||||
obligation,
|
||||
bound,
|
||||
placeholder_trait_predicate.trait_ref,
|
||||
) {
|
||||
Ok(None) => true,
|
||||
Ok(Some(normalized_trait))
|
||||
if distinct_normalized_bounds.insert(normalized_trait) =>
|
||||
{
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}) {
|
||||
return Some(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
});
|
||||
None
|
||||
})
|
||||
.collect();
|
||||
|
||||
debug!(
|
||||
"match_projection_obligation_against_definition_bounds: \
|
||||
matching_bound={:?}",
|
||||
matching_bound
|
||||
matching_bounds={:?}",
|
||||
matching_bounds
|
||||
);
|
||||
match matching_bound {
|
||||
None => false,
|
||||
Some(bound) => {
|
||||
// Repeat the successful match, if any, this time outside of a probe.
|
||||
let result =
|
||||
self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref);
|
||||
|
||||
assert!(result);
|
||||
true
|
||||
}
|
||||
}
|
||||
matching_bounds
|
||||
}
|
||||
|
||||
/// Equates the trait in `obligation` with trait bound. If the two traits
|
||||
/// can be equated and the normalized trait bound doesn't contain inference
|
||||
/// variables or placeholders, the normalized bound is returned.
|
||||
fn match_projection(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
trait_bound: ty::PolyTraitRef<'tcx>,
|
||||
placeholder_trait_ref: ty::TraitRef<'tcx>,
|
||||
) -> bool {
|
||||
) -> Result<Option<ty::PolyTraitRef<'tcx>>, ()> {
|
||||
debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
|
||||
if placeholder_trait_ref.def_id != trait_bound.def_id() {
|
||||
// Avoid unnecessary normalization
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let Normalized { value: trait_bound, obligations: _ } = ensure_sufficient_stack(|| {
|
||||
project::normalize_with_depth(
|
||||
self,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
&trait_bound,
|
||||
)
|
||||
});
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
|
||||
.is_ok()
|
||||
.map(|InferOk { obligations: _, value: () }| {
|
||||
// This method is called within a probe, so we can't have
|
||||
// inference variables and placeholders escape.
|
||||
if !trait_bound.needs_infer() && !trait_bound.has_placeholders() {
|
||||
Some(trait_bound)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map_err(|_| ())
|
||||
}
|
||||
|
||||
fn evaluate_where_clause<'o>(
|
||||
@ -1235,14 +1279,50 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
) -> Result<EvaluationResult, OverflowError> {
|
||||
self.evaluation_probe(|this| {
|
||||
match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
|
||||
Ok(obligations) => {
|
||||
this.evaluate_predicates_recursively(stack.list(), obligations.into_iter())
|
||||
}
|
||||
Ok(obligations) => this.evaluate_predicates_recursively(stack.list(), obligations),
|
||||
Err(()) => Ok(EvaluatedToErr),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn match_projection_projections(
|
||||
&mut self,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
||||
data: &PolyProjectionPredicate<'tcx>,
|
||||
potentially_unnormalized_candidates: bool,
|
||||
) -> bool {
|
||||
let mut nested_obligations = Vec::new();
|
||||
let projection_ty = if potentially_unnormalized_candidates {
|
||||
ensure_sufficient_stack(|| {
|
||||
project::normalize_with_depth_to(
|
||||
self,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
&data.map_bound_ref(|data| data.projection_ty),
|
||||
&mut nested_obligations,
|
||||
)
|
||||
})
|
||||
} else {
|
||||
data.map_bound_ref(|data| data.projection_ty)
|
||||
};
|
||||
|
||||
// FIXME(generic_associated_types): Compare the whole projections
|
||||
let data_poly_trait_ref = projection_ty.map_bound(|proj| proj.trait_ref(self.tcx()));
|
||||
let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(obligation_poly_trait_ref, data_poly_trait_ref)
|
||||
.map_or(false, |InferOk { obligations, value: () }| {
|
||||
self.evaluate_predicates_recursively(
|
||||
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
|
||||
nested_obligations.into_iter().chain(obligations),
|
||||
)
|
||||
.map_or(false, |res| res.may_apply())
|
||||
})
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// WINNOW
|
||||
//
|
||||
@ -1277,18 +1357,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
//
|
||||
// This is a fix for #53123 and prevents winnowing from accidentally extending the
|
||||
// lifetime of a variable.
|
||||
match other.candidate {
|
||||
match (&other.candidate, &victim.candidate) {
|
||||
(_, AutoImplCandidate(..)) | (AutoImplCandidate(..), _) => {
|
||||
bug!(
|
||||
"default implementations shouldn't be recorded \
|
||||
when there are other valid candidates"
|
||||
);
|
||||
}
|
||||
|
||||
// (*)
|
||||
BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => true,
|
||||
ParamCandidate(ref cand) => match victim.candidate {
|
||||
AutoImplCandidate(..) => {
|
||||
bug!(
|
||||
"default implementations shouldn't be recorded \
|
||||
when there are other valid candidates"
|
||||
);
|
||||
}
|
||||
// (*)
|
||||
BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false,
|
||||
(BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate, _) => true,
|
||||
(_, BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate) => false,
|
||||
|
||||
(ParamCandidate(..), ParamCandidate(..)) => false,
|
||||
|
||||
// Global bounds from the where clause should be ignored
|
||||
// here (see issue #50825). Otherwise, we have a where
|
||||
// clause so don't go around looking for impls.
|
||||
// Arbitrarily give param candidates priority
|
||||
// over projection and object candidates.
|
||||
(
|
||||
ParamCandidate(ref cand),
|
||||
ImplCandidate(..)
|
||||
| ClosureCandidate
|
||||
| GeneratorCandidate
|
||||
@ -1296,28 +1385,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| BuiltinCandidate { .. }
|
||||
| TraitAliasCandidate(..) => {
|
||||
// Global bounds from the where clause should be ignored
|
||||
// here (see issue #50825). Otherwise, we have a where
|
||||
// clause so don't go around looking for impls.
|
||||
!is_global(cand)
|
||||
}
|
||||
ObjectCandidate | ProjectionCandidate => {
|
||||
// Arbitrarily give param candidates priority
|
||||
// over projection and object candidates.
|
||||
!is_global(cand)
|
||||
}
|
||||
ParamCandidate(..) => false,
|
||||
},
|
||||
ObjectCandidate | ProjectionCandidate => match victim.candidate {
|
||||
AutoImplCandidate(..) => {
|
||||
bug!(
|
||||
"default implementations shouldn't be recorded \
|
||||
when there are other valid candidates"
|
||||
);
|
||||
}
|
||||
// (*)
|
||||
BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false,
|
||||
| TraitAliasCandidate(..)
|
||||
| ObjectCandidate
|
||||
| ProjectionCandidate(_),
|
||||
) => !is_global(cand),
|
||||
(ObjectCandidate | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
|
||||
// Prefer these to a global where-clause bound
|
||||
// (see issue #50825).
|
||||
is_global(cand)
|
||||
}
|
||||
(
|
||||
ImplCandidate(_)
|
||||
| ClosureCandidate
|
||||
| GeneratorCandidate
|
||||
| FnPointerCandidate
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| BuiltinCandidate { has_nested: true }
|
||||
| TraitAliasCandidate(..),
|
||||
ParamCandidate(ref cand),
|
||||
) => {
|
||||
// Prefer these to a global where-clause bound
|
||||
// (see issue #50825).
|
||||
is_global(cand) && other.evaluation.must_apply_modulo_regions()
|
||||
}
|
||||
|
||||
(ProjectionCandidate(i), ProjectionCandidate(j)) => {
|
||||
// Arbitrarily pick the first candidate for backwards
|
||||
// compatibility reasons. Don't let this affect inference.
|
||||
i > j && !needs_infer
|
||||
}
|
||||
(ObjectCandidate, ObjectCandidate) => bug!("Duplicate object candidate"),
|
||||
(ObjectCandidate, ProjectionCandidate(_))
|
||||
| (ProjectionCandidate(_), ObjectCandidate) => {
|
||||
bug!("Have both object and projection candidate")
|
||||
}
|
||||
|
||||
// Arbitrarily give projection and object candidates priority.
|
||||
(
|
||||
ObjectCandidate | ProjectionCandidate(_),
|
||||
ImplCandidate(..)
|
||||
| ClosureCandidate
|
||||
| GeneratorCandidate
|
||||
@ -1325,98 +1431,100 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| BuiltinCandidate { .. }
|
||||
| TraitAliasCandidate(..) => true,
|
||||
ObjectCandidate | ProjectionCandidate => {
|
||||
// Arbitrarily give param candidates priority
|
||||
// over projection and object candidates.
|
||||
true
|
||||
}
|
||||
ParamCandidate(ref cand) => is_global(cand),
|
||||
},
|
||||
ImplCandidate(other_def) => {
|
||||
| TraitAliasCandidate(..),
|
||||
) => true,
|
||||
|
||||
(
|
||||
ImplCandidate(..)
|
||||
| ClosureCandidate
|
||||
| GeneratorCandidate
|
||||
| FnPointerCandidate
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| BuiltinCandidate { .. }
|
||||
| TraitAliasCandidate(..),
|
||||
ObjectCandidate | ProjectionCandidate(_),
|
||||
) => false,
|
||||
|
||||
(&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
|
||||
// See if we can toss out `victim` based on specialization.
|
||||
// This requires us to know *for sure* that the `other` impl applies
|
||||
// i.e., `EvaluatedToOk`.
|
||||
if other.evaluation.must_apply_modulo_regions() {
|
||||
match victim.candidate {
|
||||
ImplCandidate(victim_def) => {
|
||||
let tcx = self.tcx();
|
||||
if tcx.specializes((other_def, victim_def)) {
|
||||
return true;
|
||||
}
|
||||
return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
|
||||
Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
|
||||
// Subtle: If the predicate we are evaluating has inference
|
||||
// variables, do *not* allow discarding candidates due to
|
||||
// marker trait impls.
|
||||
//
|
||||
// Without this restriction, we could end up accidentally
|
||||
// constrainting inference variables based on an arbitrarily
|
||||
// chosen trait impl.
|
||||
//
|
||||
// Imagine we have the following code:
|
||||
//
|
||||
// ```rust
|
||||
// #[marker] trait MyTrait {}
|
||||
// impl MyTrait for u8 {}
|
||||
// impl MyTrait for bool {}
|
||||
// ```
|
||||
//
|
||||
// And we are evaluating the predicate `<_#0t as MyTrait>`.
|
||||
//
|
||||
// During selection, we will end up with one candidate for each
|
||||
// impl of `MyTrait`. If we were to discard one impl in favor
|
||||
// of the other, we would be left with one candidate, causing
|
||||
// us to "successfully" select the predicate, unifying
|
||||
// _#0t with (for example) `u8`.
|
||||
//
|
||||
// However, we have no reason to believe that this unification
|
||||
// is correct - we've essentially just picked an arbitrary
|
||||
// *possibility* for _#0t, and required that this be the *only*
|
||||
// possibility.
|
||||
//
|
||||
// Eventually, we will either:
|
||||
// 1) Unify all inference variables in the predicate through
|
||||
// some other means (e.g. type-checking of a function). We will
|
||||
// then be in a position to drop marker trait candidates
|
||||
// without constraining inference variables (since there are
|
||||
// none left to constrin)
|
||||
// 2) Be left with some unconstrained inference variables. We
|
||||
// will then correctly report an inference error, since the
|
||||
// existence of multiple marker trait impls tells us nothing
|
||||
// about which one should actually apply.
|
||||
!needs_infer
|
||||
}
|
||||
Some(_) => true,
|
||||
None => false,
|
||||
};
|
||||
}
|
||||
ParamCandidate(ref cand) => {
|
||||
// Prefer the impl to a global where clause candidate.
|
||||
return is_global(cand);
|
||||
}
|
||||
_ => (),
|
||||
let tcx = self.tcx();
|
||||
if tcx.specializes((other_def, victim_def)) {
|
||||
return true;
|
||||
}
|
||||
return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
|
||||
Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
|
||||
// Subtle: If the predicate we are evaluating has inference
|
||||
// variables, do *not* allow discarding candidates due to
|
||||
// marker trait impls.
|
||||
//
|
||||
// Without this restriction, we could end up accidentally
|
||||
// constrainting inference variables based on an arbitrarily
|
||||
// chosen trait impl.
|
||||
//
|
||||
// Imagine we have the following code:
|
||||
//
|
||||
// ```rust
|
||||
// #[marker] trait MyTrait {}
|
||||
// impl MyTrait for u8 {}
|
||||
// impl MyTrait for bool {}
|
||||
// ```
|
||||
//
|
||||
// And we are evaluating the predicate `<_#0t as MyTrait>`.
|
||||
//
|
||||
// During selection, we will end up with one candidate for each
|
||||
// impl of `MyTrait`. If we were to discard one impl in favor
|
||||
// of the other, we would be left with one candidate, causing
|
||||
// us to "successfully" select the predicate, unifying
|
||||
// _#0t with (for example) `u8`.
|
||||
//
|
||||
// However, we have no reason to believe that this unification
|
||||
// is correct - we've essentially just picked an arbitrary
|
||||
// *possibility* for _#0t, and required that this be the *only*
|
||||
// possibility.
|
||||
//
|
||||
// Eventually, we will either:
|
||||
// 1) Unify all inference variables in the predicate through
|
||||
// some other means (e.g. type-checking of a function). We will
|
||||
// then be in a position to drop marker trait candidates
|
||||
// without constraining inference variables (since there are
|
||||
// none left to constrin)
|
||||
// 2) Be left with some unconstrained inference variables. We
|
||||
// will then correctly report an inference error, since the
|
||||
// existence of multiple marker trait impls tells us nothing
|
||||
// about which one should actually apply.
|
||||
!needs_infer
|
||||
}
|
||||
Some(_) => true,
|
||||
None => false,
|
||||
};
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
ClosureCandidate
|
||||
| GeneratorCandidate
|
||||
| FnPointerCandidate
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| BuiltinCandidate { has_nested: true } => {
|
||||
match victim.candidate {
|
||||
ParamCandidate(ref cand) => {
|
||||
// Prefer these to a global where-clause bound
|
||||
// (see issue #50825).
|
||||
is_global(cand) && other.evaluation.must_apply_modulo_regions()
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
// Everything else is ambiguous
|
||||
(
|
||||
ImplCandidate(_)
|
||||
| ClosureCandidate
|
||||
| GeneratorCandidate
|
||||
| FnPointerCandidate
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| BuiltinCandidate { has_nested: true }
|
||||
| TraitAliasCandidate(..),
|
||||
ImplCandidate(_)
|
||||
| ClosureCandidate
|
||||
| GeneratorCandidate
|
||||
| FnPointerCandidate
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| BuiltinCandidate { has_nested: true }
|
||||
| TraitAliasCandidate(..),
|
||||
) => false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1649,7 +1757,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/
|
||||
|
||||
self.infcx.commit_unconditionally(|_| {
|
||||
let (placeholder_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty);
|
||||
let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(&ty);
|
||||
let Normalized { value: normalized_ty, mut obligations } =
|
||||
ensure_sufficient_stack(|| {
|
||||
project::normalize_with_depth(
|
||||
@ -1717,7 +1825,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let (placeholder_obligation, _) =
|
||||
let placeholder_obligation =
|
||||
self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
|
||||
let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref;
|
||||
|
||||
|
@ -20,6 +20,7 @@ pub fn obligations<'a, 'tcx>(
|
||||
infcx: &InferCtxt<'a, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body_id: hir::HirId,
|
||||
recursion_depth: usize,
|
||||
arg: GenericArg<'tcx>,
|
||||
span: Span,
|
||||
) -> Option<Vec<traits::PredicateObligation<'tcx>>> {
|
||||
@ -59,7 +60,8 @@ pub fn obligations<'a, 'tcx>(
|
||||
GenericArgKind::Lifetime(..) => return Some(Vec::new()),
|
||||
};
|
||||
|
||||
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
|
||||
let mut wf =
|
||||
WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth, item: None };
|
||||
wf.compute(arg);
|
||||
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
|
||||
|
||||
@ -80,7 +82,8 @@ pub fn trait_obligations<'a, 'tcx>(
|
||||
span: Span,
|
||||
item: Option<&'tcx hir::Item<'tcx>>,
|
||||
) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item };
|
||||
let mut wf =
|
||||
WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth: 0, item };
|
||||
wf.compute_trait_ref(trait_ref, Elaborate::All);
|
||||
wf.normalize()
|
||||
}
|
||||
@ -92,7 +95,15 @@ pub fn predicate_obligations<'a, 'tcx>(
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
span: Span,
|
||||
) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
|
||||
let mut wf = WfPredicates {
|
||||
infcx,
|
||||
param_env,
|
||||
body_id,
|
||||
span,
|
||||
out: vec![],
|
||||
recursion_depth: 0,
|
||||
item: None,
|
||||
};
|
||||
|
||||
// It's ok to skip the binder here because wf code is prepared for it
|
||||
match predicate.skip_binders() {
|
||||
@ -142,6 +153,7 @@ struct WfPredicates<'a, 'tcx> {
|
||||
body_id: hir::HirId,
|
||||
span: Span,
|
||||
out: Vec<traits::PredicateObligation<'tcx>>,
|
||||
recursion_depth: usize,
|
||||
item: Option<&'tcx hir::Item<'tcx>>,
|
||||
}
|
||||
|
||||
@ -241,18 +253,27 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
traits::ObligationCause::new(self.span, self.body_id, code)
|
||||
}
|
||||
|
||||
fn normalize(&mut self) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||
fn normalize(mut self) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||
let cause = self.cause(traits::MiscObligation);
|
||||
let infcx = &mut self.infcx;
|
||||
let param_env = self.param_env;
|
||||
let mut obligations = Vec::with_capacity(self.out.len());
|
||||
for pred in &self.out {
|
||||
assert!(!pred.has_escaping_bound_vars());
|
||||
for mut obligation in self.out {
|
||||
assert!(!obligation.has_escaping_bound_vars());
|
||||
let mut selcx = traits::SelectionContext::new(infcx);
|
||||
let i = obligations.len();
|
||||
let value =
|
||||
traits::normalize_to(&mut selcx, param_env, cause.clone(), pred, &mut obligations);
|
||||
obligations.insert(i, value);
|
||||
// Don't normalize the whole obligation, the param env is either
|
||||
// already normalized, or we're currently normalizing the
|
||||
// param_env. Either way we should only normalize the predicate.
|
||||
let normalized_predicate = traits::project::normalize_with_depth_to(
|
||||
&mut selcx,
|
||||
param_env,
|
||||
cause.clone(),
|
||||
self.recursion_depth,
|
||||
&obligation.predicate,
|
||||
&mut obligations,
|
||||
);
|
||||
obligation.predicate = normalized_predicate;
|
||||
obligations.push(obligation);
|
||||
}
|
||||
obligations
|
||||
}
|
||||
@ -265,6 +286,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
debug!("compute_trait_ref obligations {:?}", obligations);
|
||||
let cause = self.cause(traits::MiscObligation);
|
||||
let param_env = self.param_env;
|
||||
let depth = self.recursion_depth;
|
||||
|
||||
let item = self.item;
|
||||
|
||||
@ -286,7 +308,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
&obligation.predicate,
|
||||
tcx.associated_items(trait_ref.def_id).in_definition_order(),
|
||||
);
|
||||
traits::Obligation::new(cause, param_env, obligation.predicate)
|
||||
traits::Obligation::with_depth(cause, depth, param_env, obligation.predicate)
|
||||
};
|
||||
|
||||
if let Elaborate::All = elaborate {
|
||||
@ -315,8 +337,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
new_cause.make_mut().span = self_ty.span;
|
||||
}
|
||||
}
|
||||
traits::Obligation::new(
|
||||
traits::Obligation::with_depth(
|
||||
new_cause,
|
||||
depth,
|
||||
param_env,
|
||||
ty::PredicateAtom::WellFormed(arg).to_predicate(tcx),
|
||||
)
|
||||
@ -327,17 +350,51 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
/// Pushes the obligations required for `trait_ref::Item` to be WF
|
||||
/// into `self.out`.
|
||||
fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) {
|
||||
// A projection is well-formed if (a) the trait ref itself is
|
||||
// WF and (b) the trait-ref holds. (It may also be
|
||||
// normalizable and be WF that way.)
|
||||
let trait_ref = data.trait_ref(self.infcx.tcx);
|
||||
self.compute_trait_ref(&trait_ref, Elaborate::None);
|
||||
// A projection is well-formed if
|
||||
//
|
||||
// (a) its predicates hold (*)
|
||||
// (b) its substs are wf
|
||||
//
|
||||
// (*) The predicates of an associated type include the predicates of
|
||||
// the trait that it's contained in. For example, given
|
||||
//
|
||||
// trait A<T>: Clone {
|
||||
// type X where T: Copy;
|
||||
// }
|
||||
//
|
||||
// The predicates of `<() as A<i32>>::X` are:
|
||||
// [
|
||||
// `(): Sized`
|
||||
// `(): Clone`
|
||||
// `(): A<i32>`
|
||||
// `i32: Sized`
|
||||
// `i32: Clone`
|
||||
// `i32: Copy`
|
||||
// ]
|
||||
let obligations = self.nominal_obligations(data.item_def_id, data.substs);
|
||||
self.out.extend(obligations);
|
||||
|
||||
if !data.has_escaping_bound_vars() {
|
||||
let predicate = trait_ref.without_const().to_predicate(self.infcx.tcx);
|
||||
let cause = self.cause(traits::ProjectionWf(data));
|
||||
self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
|
||||
}
|
||||
let tcx = self.tcx();
|
||||
let cause = self.cause(traits::MiscObligation);
|
||||
let param_env = self.param_env;
|
||||
let depth = self.recursion_depth;
|
||||
|
||||
self.out.extend(
|
||||
data.substs
|
||||
.iter()
|
||||
.filter(|arg| {
|
||||
matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
|
||||
})
|
||||
.filter(|arg| !arg.has_escaping_bound_vars())
|
||||
.map(|arg| {
|
||||
traits::Obligation::with_depth(
|
||||
cause.clone(),
|
||||
depth,
|
||||
param_env,
|
||||
ty::PredicateAtom::WellFormed(arg).to_predicate(tcx),
|
||||
)
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
|
||||
@ -347,8 +404,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
def_id: self.infcx.tcx.require_lang_item(LangItem::Sized, None),
|
||||
substs: self.infcx.tcx.mk_substs_trait(subty, &[]),
|
||||
};
|
||||
self.out.push(traits::Obligation::new(
|
||||
self.out.push(traits::Obligation::with_depth(
|
||||
cause,
|
||||
self.recursion_depth,
|
||||
self.param_env,
|
||||
trait_ref.without_const().to_predicate(self.infcx.tcx),
|
||||
));
|
||||
@ -359,6 +417,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
fn compute(&mut self, arg: GenericArg<'tcx>) {
|
||||
let mut walker = arg.walk();
|
||||
let param_env = self.param_env;
|
||||
let depth = self.recursion_depth;
|
||||
while let Some(arg) = walker.next() {
|
||||
let ty = match arg.unpack() {
|
||||
GenericArgKind::Type(ty) => ty,
|
||||
@ -378,8 +437,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
let predicate = ty::PredicateAtom::ConstEvaluatable(def, substs)
|
||||
.to_predicate(self.tcx());
|
||||
let cause = self.cause(traits::MiscObligation);
|
||||
self.out.push(traits::Obligation::new(
|
||||
self.out.push(traits::Obligation::with_depth(
|
||||
cause,
|
||||
self.recursion_depth,
|
||||
self.param_env,
|
||||
predicate,
|
||||
));
|
||||
@ -394,8 +454,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
val: ty::ConstKind::Infer(resolved),
|
||||
..*constant
|
||||
});
|
||||
self.out.push(traits::Obligation::new(
|
||||
self.out.push(traits::Obligation::with_depth(
|
||||
cause,
|
||||
self.recursion_depth,
|
||||
self.param_env,
|
||||
ty::PredicateAtom::WellFormed(resolved_constant.into())
|
||||
.to_predicate(self.tcx()),
|
||||
@ -480,8 +541,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
// WfReference
|
||||
if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() {
|
||||
let cause = self.cause(traits::ReferenceOutlivesReferent(ty));
|
||||
self.out.push(traits::Obligation::new(
|
||||
self.out.push(traits::Obligation::with_depth(
|
||||
cause,
|
||||
depth,
|
||||
param_env,
|
||||
ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(rty, r))
|
||||
.to_predicate(self.tcx()),
|
||||
@ -571,8 +633,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
let component_traits = data.auto_traits().chain(data.principal_def_id());
|
||||
let tcx = self.tcx();
|
||||
self.out.extend(component_traits.map(|did| {
|
||||
traits::Obligation::new(
|
||||
traits::Obligation::with_depth(
|
||||
cause.clone(),
|
||||
depth,
|
||||
param_env,
|
||||
ty::PredicateAtom::ObjectSafe(did).to_predicate(tcx),
|
||||
)
|
||||
@ -597,8 +660,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
if let ty::Infer(ty::TyVar(_)) = ty.kind() {
|
||||
// Not yet resolved, but we've made progress.
|
||||
let cause = self.cause(traits::MiscObligation);
|
||||
self.out.push(traits::Obligation::new(
|
||||
self.out.push(traits::Obligation::with_depth(
|
||||
cause,
|
||||
self.recursion_depth,
|
||||
param_env,
|
||||
ty::PredicateAtom::WellFormed(ty.into()).to_predicate(self.tcx()),
|
||||
));
|
||||
@ -635,7 +699,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
.zip(origins.into_iter().rev())
|
||||
.map(|((pred, span), origin_def_id)| {
|
||||
let cause = self.cause(traits::BindingObligation(origin_def_id, span));
|
||||
traits::Obligation::new(cause, self.param_env, pred)
|
||||
traits::Obligation::with_depth(cause, self.recursion_depth, self.param_env, pred)
|
||||
})
|
||||
.filter(|pred| !pred.has_escaping_bound_vars())
|
||||
.collect()
|
||||
@ -688,8 +752,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound));
|
||||
let outlives =
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound));
|
||||
self.out.push(traits::Obligation::new(
|
||||
self.out.push(traits::Obligation::with_depth(
|
||||
cause,
|
||||
self.recursion_depth,
|
||||
self.param_env,
|
||||
outlives.to_predicate(self.infcx.tcx),
|
||||
));
|
||||
|
@ -50,6 +50,19 @@ impl<'tcx> RustIrDatabase<'tcx> {
|
||||
.map(|wc| wc.fold_with(&mut regions_substitutor))
|
||||
.filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect()
|
||||
}
|
||||
|
||||
fn bounds_for<T>(&self, def_id: DefId, bound_vars: SubstsRef<'tcx>) -> Vec<T>
|
||||
where
|
||||
ty::Predicate<'tcx>: LowerInto<'tcx, std::option::Option<T>>,
|
||||
{
|
||||
self.interner
|
||||
.tcx
|
||||
.explicit_item_bounds(def_id)
|
||||
.iter()
|
||||
.map(|(bound, _)| bound.subst(self.interner.tcx, &bound_vars))
|
||||
.filter_map(|bound| LowerInto::<Option<_>>::lower_into(bound, &self.interner))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'tcx> {
|
||||
@ -73,10 +86,9 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
|
||||
}
|
||||
let bound_vars = bound_vars_for_item(self.interner.tcx, def_id);
|
||||
let binders = binders_for(&self.interner, bound_vars);
|
||||
// FIXME(chalk): this really isn't right I don't think. The functions
|
||||
// for GATs are a bit hard to figure out. Are these supposed to be where
|
||||
// clauses or bounds?
|
||||
|
||||
let where_clauses = self.where_clauses_for(def_id, bound_vars);
|
||||
let bounds = self.bounds_for(def_id, bound_vars);
|
||||
|
||||
Arc::new(chalk_solve::rust_ir::AssociatedTyDatum {
|
||||
trait_id: chalk_ir::TraitId(trait_def_id),
|
||||
@ -84,7 +96,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
|
||||
name: (),
|
||||
binders: chalk_ir::Binders::new(
|
||||
binders,
|
||||
chalk_solve::rust_ir::AssociatedTyDatumBound { bounds: vec![], where_clauses },
|
||||
chalk_solve::rust_ir::AssociatedTyDatumBound { bounds, where_clauses },
|
||||
),
|
||||
})
|
||||
}
|
||||
@ -442,11 +454,13 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
|
||||
let bound_vars = bound_vars_for_item(self.interner.tcx, opaque_ty_id.0);
|
||||
let binders = binders_for(&self.interner, bound_vars);
|
||||
let where_clauses = self.where_clauses_for(opaque_ty_id.0, bound_vars);
|
||||
let bounds = self.bounds_for(opaque_ty_id.0, bound_vars);
|
||||
|
||||
let value = chalk_solve::rust_ir::OpaqueTyDatumBound {
|
||||
bounds: chalk_ir::Binders::new(binders.clone(), vec![]),
|
||||
bounds: chalk_ir::Binders::new(binders.clone(), bounds),
|
||||
where_clauses: chalk_ir::Binders::new(binders, where_clauses),
|
||||
};
|
||||
|
||||
Arc::new(chalk_solve::rust_ir::OpaqueTyDatum {
|
||||
opaque_ty_id,
|
||||
bound: chalk_ir::Binders::empty(&self.interner, value),
|
||||
|
@ -728,6 +728,87 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::FnSig<RustInterner<'tcx>>> for ty::Binder<t
|
||||
}
|
||||
}
|
||||
|
||||
// We lower into an Option here since there are some predicates which Chalk
|
||||
// doesn't have a representation for yet (as an `InlineBound`). The `Option` will
|
||||
// eventually be removed.
|
||||
impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<RustInterner<'tcx>>>>
|
||||
for ty::Predicate<'tcx>
|
||||
{
|
||||
fn lower_into(
|
||||
self,
|
||||
interner: &RustInterner<'tcx>,
|
||||
) -> Option<chalk_solve::rust_ir::QuantifiedInlineBound<RustInterner<'tcx>>> {
|
||||
match self.bound_atom(interner.tcx).skip_binder() {
|
||||
ty::PredicateAtom::Trait(predicate, _) => {
|
||||
let (predicate, binders, _named_regions) =
|
||||
collect_bound_vars(interner, interner.tcx, &ty::Binder::bind(predicate));
|
||||
|
||||
Some(chalk_ir::Binders::new(
|
||||
binders,
|
||||
chalk_solve::rust_ir::InlineBound::TraitBound(
|
||||
predicate.trait_ref.lower_into(interner),
|
||||
),
|
||||
))
|
||||
}
|
||||
ty::PredicateAtom::Projection(predicate) => {
|
||||
let (predicate, binders, _named_regions) =
|
||||
collect_bound_vars(interner, interner.tcx, &ty::Binder::bind(predicate));
|
||||
|
||||
Some(chalk_ir::Binders::new(
|
||||
binders,
|
||||
chalk_solve::rust_ir::InlineBound::AliasEqBound(predicate.lower_into(interner)),
|
||||
))
|
||||
}
|
||||
ty::PredicateAtom::TypeOutlives(_predicate) => None,
|
||||
ty::PredicateAtom::WellFormed(_ty) => None,
|
||||
|
||||
ty::PredicateAtom::RegionOutlives(..)
|
||||
| ty::PredicateAtom::ObjectSafe(..)
|
||||
| ty::PredicateAtom::ClosureKind(..)
|
||||
| ty::PredicateAtom::Subtype(..)
|
||||
| ty::PredicateAtom::ConstEvaluatable(..)
|
||||
| ty::PredicateAtom::ConstEquate(..)
|
||||
| ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
|
||||
bug!("unexpected predicate {}", &self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::TraitBound<RustInterner<'tcx>>>
|
||||
for ty::TraitRef<'tcx>
|
||||
{
|
||||
fn lower_into(
|
||||
self,
|
||||
interner: &RustInterner<'tcx>,
|
||||
) -> chalk_solve::rust_ir::TraitBound<RustInterner<'tcx>> {
|
||||
chalk_solve::rust_ir::TraitBound {
|
||||
trait_id: chalk_ir::TraitId(self.def_id),
|
||||
args_no_self: self.substs[1..].iter().map(|arg| arg.lower_into(interner)).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>>>
|
||||
for ty::ProjectionPredicate<'tcx>
|
||||
{
|
||||
fn lower_into(
|
||||
self,
|
||||
interner: &RustInterner<'tcx>,
|
||||
) -> chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>> {
|
||||
let trait_ref = self.projection_ty.trait_ref(interner.tcx);
|
||||
chalk_solve::rust_ir::AliasEqBound {
|
||||
trait_bound: trait_ref.lower_into(interner),
|
||||
associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
|
||||
parameters: self.projection_ty.substs[trait_ref.substs.len()..]
|
||||
.iter()
|
||||
.map(|arg| arg.lower_into(interner))
|
||||
.collect(),
|
||||
value: self.ty.lower_into(interner),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// To collect bound vars, we have to do two passes. In the first pass, we
|
||||
/// collect all `BoundRegion`s and `ty::Bound`s. In the second pass, we then
|
||||
/// replace `BrNamed` into `BrAnon`. The two separate passes are important,
|
||||
|
@ -61,8 +61,8 @@ fn compute_implied_outlives_bounds<'tcx>(
|
||||
// than the ultimate set. (Note: normally there won't be
|
||||
// unresolved inference variables here anyway, but there might be
|
||||
// during typeck under some circumstances.)
|
||||
let obligations =
|
||||
wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, arg, DUMMY_SP).unwrap_or(vec![]);
|
||||
let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP)
|
||||
.unwrap_or(vec![]);
|
||||
|
||||
// N.B., all of these predicates *ought* to be easily proven
|
||||
// true. In fact, their correctness is (mostly) implied by
|
||||
|
@ -1,11 +1,9 @@
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
|
||||
use rustc_infer::traits::util;
|
||||
use rustc_middle::hir::map as hir_map;
|
||||
use rustc_middle::ty::subst::{InternalSubsts, Subst};
|
||||
use rustc_middle::ty::subst::Subst;
|
||||
use rustc_middle::ty::{
|
||||
self, Binder, Predicate, PredicateAtom, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
|
||||
};
|
||||
@ -492,133 +490,6 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
|
||||
fn_like.asyncness()
|
||||
}
|
||||
|
||||
/// For associated types we allow bounds written on the associated type
|
||||
/// (`type X: Trait`) to be used as candidates. We also allow the same bounds
|
||||
/// when desugared as bounds on the trait `where Self::X: Trait`.
|
||||
///
|
||||
/// Note that this filtering is done with the items identity substs to
|
||||
/// simplify checking that these bounds are met in impls. This means that
|
||||
/// a bound such as `for<'b> <Self as X<'b>>::U: Clone` can't be used, as in
|
||||
/// `hr-associated-type-bound-1.rs`.
|
||||
fn associated_type_projection_predicates(
|
||||
tcx: TyCtxt<'_>,
|
||||
assoc_item_def_id: DefId,
|
||||
) -> &'_ ty::List<ty::Predicate<'_>> {
|
||||
let generic_trait_bounds = tcx.predicates_of(assoc_item_def_id);
|
||||
// We include predicates from the trait as well to handle
|
||||
// `where Self::X: Trait`.
|
||||
let item_bounds = generic_trait_bounds.instantiate_identity(tcx);
|
||||
let item_predicates = util::elaborate_predicates(tcx, item_bounds.predicates.into_iter());
|
||||
|
||||
let assoc_item_ty = ty::ProjectionTy {
|
||||
item_def_id: assoc_item_def_id,
|
||||
substs: InternalSubsts::identity_for_item(tcx, assoc_item_def_id),
|
||||
};
|
||||
|
||||
let predicates = item_predicates.filter_map(|obligation| {
|
||||
let pred = obligation.predicate;
|
||||
match pred.skip_binders() {
|
||||
ty::PredicateAtom::Trait(tr, _) => {
|
||||
if let ty::Projection(p) = *tr.self_ty().kind() {
|
||||
if p == assoc_item_ty {
|
||||
return Some(pred);
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::PredicateAtom::Projection(proj) => {
|
||||
if let ty::Projection(p) = *proj.projection_ty.self_ty().kind() {
|
||||
if p == assoc_item_ty {
|
||||
return Some(pred);
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::PredicateAtom::TypeOutlives(outlives) => {
|
||||
if let ty::Projection(p) = *outlives.0.kind() {
|
||||
if p == assoc_item_ty {
|
||||
return Some(pred);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
None
|
||||
});
|
||||
|
||||
let result = tcx.mk_predicates(predicates);
|
||||
debug!(
|
||||
"associated_type_projection_predicates({}) = {:?}",
|
||||
tcx.def_path_str(assoc_item_def_id),
|
||||
result
|
||||
);
|
||||
result
|
||||
}
|
||||
|
||||
/// Opaque types don't have the same issues as associated types: the only
|
||||
/// predicates on an opaque type (excluding those it inherits from its parent
|
||||
/// item) should be of the form we're expecting.
|
||||
fn opaque_type_projection_predicates(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: DefId,
|
||||
) -> &'_ ty::List<ty::Predicate<'_>> {
|
||||
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||
|
||||
let bounds = tcx.predicates_of(def_id);
|
||||
let predicates =
|
||||
util::elaborate_predicates(tcx, bounds.predicates.iter().map(|&(pred, _)| pred));
|
||||
|
||||
let filtered_predicates = predicates.filter_map(|obligation| {
|
||||
let pred = obligation.predicate;
|
||||
match pred.skip_binders() {
|
||||
ty::PredicateAtom::Trait(tr, _) => {
|
||||
if let ty::Opaque(opaque_def_id, opaque_substs) = *tr.self_ty().kind() {
|
||||
if opaque_def_id == def_id && opaque_substs == substs {
|
||||
return Some(pred);
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::PredicateAtom::Projection(proj) => {
|
||||
if let ty::Opaque(opaque_def_id, opaque_substs) =
|
||||
*proj.projection_ty.self_ty().kind()
|
||||
{
|
||||
if opaque_def_id == def_id && opaque_substs == substs {
|
||||
return Some(pred);
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::PredicateAtom::TypeOutlives(outlives) => {
|
||||
if let ty::Opaque(opaque_def_id, opaque_substs) = *outlives.0.kind() {
|
||||
if opaque_def_id == def_id && opaque_substs == substs {
|
||||
return Some(pred);
|
||||
}
|
||||
} else {
|
||||
// These can come from elaborating other predicates
|
||||
return None;
|
||||
}
|
||||
}
|
||||
// These can come from elaborating other predicates
|
||||
ty::PredicateAtom::RegionOutlives(_) => return None,
|
||||
_ => {}
|
||||
}
|
||||
tcx.sess.delay_span_bug(
|
||||
obligation.cause.span(tcx),
|
||||
&format!("unexpected predicate {:?} on opaque type", pred),
|
||||
);
|
||||
None
|
||||
});
|
||||
|
||||
let result = tcx.mk_predicates(filtered_predicates);
|
||||
debug!("opaque_type_projection_predicates({}) = {:?}", tcx.def_path_str(def_id), result);
|
||||
result
|
||||
}
|
||||
|
||||
fn projection_predicates(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List<ty::Predicate<'_>> {
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::AssocTy => associated_type_projection_predicates(tcx, def_id),
|
||||
DefKind::OpaqueTy => opaque_type_projection_predicates(tcx, def_id),
|
||||
k => bug!("projection_predicates called on {}", k.descr(def_id)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut ty::query::Providers) {
|
||||
*providers = ty::query::Providers {
|
||||
asyncness,
|
||||
@ -636,7 +507,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
|
||||
instance_def_size_estimate,
|
||||
issue33140_self_ty,
|
||||
impl_defaultness,
|
||||
projection_predicates,
|
||||
..*providers
|
||||
};
|
||||
}
|
||||
|
@ -71,12 +71,8 @@ impl<'tcx> Bounds<'tcx> {
|
||||
self.region_bounds
|
||||
.iter()
|
||||
.map(|&(region_bound, span)| {
|
||||
// Account for the binder being introduced below; no need to shift `param_ty`
|
||||
// because, at present at least, it either only refers to early-bound regions,
|
||||
// or it's a generic associated type that deliberately has escaping bound vars.
|
||||
let region_bound = ty::fold::shift_region(tcx, region_bound, 1);
|
||||
let outlives = ty::OutlivesPredicate(param_ty, region_bound);
|
||||
(ty::Binder::bind(outlives).to_predicate(tcx), span)
|
||||
(ty::Binder::dummy(outlives).to_predicate(tcx), span)
|
||||
})
|
||||
.chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
|
||||
let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
|
||||
|
@ -1,15 +1,16 @@
|
||||
use super::coercion::CoerceMany;
|
||||
use super::compare_method::check_type_bounds;
|
||||
use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl};
|
||||
use super::*;
|
||||
|
||||
use rustc_attr as attr;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_errors::{Applicability, ErrorReported};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{ItemKind, Node};
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::RegionVariableOrigin;
|
||||
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::util::{Discr, IntTypeExt, Representability};
|
||||
@ -18,6 +19,8 @@ use rustc_session::config::EntryFnType;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{self, MultiSpan, Span};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::opaque_types::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{self, ObligationCauseCode};
|
||||
|
||||
pub fn check_wf_new(tcx: TyCtxt<'_>) {
|
||||
@ -385,8 +388,13 @@ pub(super) fn check_opaque<'tcx>(
|
||||
origin: &hir::OpaqueTyOrigin,
|
||||
) {
|
||||
check_opaque_for_inheriting_lifetimes(tcx, def_id, span);
|
||||
tcx.ensure().type_of(def_id);
|
||||
check_opaque_for_cycles(tcx, def_id, substs, span, origin);
|
||||
if tcx.type_of(def_id).references_error() {
|
||||
return;
|
||||
}
|
||||
if check_opaque_for_cycles(tcx, def_id, substs, span, origin).is_err() {
|
||||
return;
|
||||
}
|
||||
check_opaque_meets_bounds(tcx, def_id, substs, span, origin);
|
||||
}
|
||||
|
||||
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
|
||||
@ -453,8 +461,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
|
||||
ty: None,
|
||||
};
|
||||
let prohibit_opaque = tcx
|
||||
.predicates_of(def_id)
|
||||
.predicates
|
||||
.explicit_item_bounds(def_id)
|
||||
.iter()
|
||||
.any(|(predicate, _)| predicate.visit_with(&mut visitor));
|
||||
debug!(
|
||||
@ -476,7 +483,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
|
||||
span,
|
||||
E0760,
|
||||
"`{}` return type cannot contain a projection or `Self` that references lifetimes from \
|
||||
a parent scope",
|
||||
a parent scope",
|
||||
if is_async { "async fn" } else { "impl Trait" },
|
||||
);
|
||||
|
||||
@ -504,7 +511,7 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
|
||||
substs: SubstsRef<'tcx>,
|
||||
span: Span,
|
||||
origin: &hir::OpaqueTyOrigin,
|
||||
) {
|
||||
) -> Result<(), ErrorReported> {
|
||||
if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs)
|
||||
{
|
||||
match origin {
|
||||
@ -514,9 +521,82 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
|
||||
}
|
||||
_ => opaque_type_cycle_error(tcx, def_id, span),
|
||||
}
|
||||
Err(ErrorReported)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that the concrete type behind `impl Trait` actually implements `Trait`.
|
||||
///
|
||||
/// This is mostly checked at the places that specify the opaque type, but we
|
||||
/// check those cases in the `param_env` of that function, which may have
|
||||
/// bounds not on this opaque type:
|
||||
///
|
||||
/// type X<T> = impl Clone
|
||||
/// fn f<T: Clone>(t: T) -> X<T> {
|
||||
/// t
|
||||
/// }
|
||||
///
|
||||
/// Without this check the above code is incorrectly accepted: we would ICE if
|
||||
/// some tried, for example, to clone an `Option<X<&mut ()>>`.
|
||||
fn check_opaque_meets_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
substs: SubstsRef<'tcx>,
|
||||
span: Span,
|
||||
origin: &hir::OpaqueTyOrigin,
|
||||
) {
|
||||
match origin {
|
||||
// Checked when type checking the function containing them.
|
||||
hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => return,
|
||||
// Can have different predicates to their defining use
|
||||
hir::OpaqueTyOrigin::Binding | hir::OpaqueTyOrigin::Misc => {}
|
||||
}
|
||||
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let param_env = tcx.param_env(def_id);
|
||||
|
||||
tcx.infer_ctxt().enter(move |infcx| {
|
||||
let inh = Inherited::new(infcx, def_id);
|
||||
let infcx = &inh.infcx;
|
||||
let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
|
||||
|
||||
let misc_cause = traits::ObligationCause::misc(span, hir_id);
|
||||
|
||||
let (_, opaque_type_map) = inh.register_infer_ok_obligations(
|
||||
infcx.instantiate_opaque_types(def_id, hir_id, param_env, &opaque_ty, span),
|
||||
);
|
||||
|
||||
for (def_id, opaque_defn) in opaque_type_map {
|
||||
match infcx
|
||||
.at(&misc_cause, param_env)
|
||||
.eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, opaque_defn.substs))
|
||||
{
|
||||
Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
|
||||
Err(ty_err) => tcx.sess.delay_span_bug(
|
||||
opaque_defn.definition_span,
|
||||
&format!(
|
||||
"could not unify `{}` with revealed type:\n{}",
|
||||
opaque_defn.concrete_ty, ty_err,
|
||||
),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
// version.
|
||||
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
|
||||
infcx.report_fulfillment_errors(errors, None, false);
|
||||
}
|
||||
|
||||
// Finally, resolve all regions. This catches wily misuses of
|
||||
// lifetime parameters.
|
||||
let fcx = FnCtxt::new(&inh, param_env, hir_id);
|
||||
fcx.regionck_item(hir_id, span, &[]);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
|
||||
debug!(
|
||||
"check_item_type(it.hir_id={}, it.name={})",
|
||||
@ -553,9 +633,25 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
|
||||
|
||||
for item in items.iter() {
|
||||
let item = tcx.hir().trait_item(item.id);
|
||||
if let hir::TraitItemKind::Fn(sig, _) = &item.kind {
|
||||
let abi = sig.header.abi;
|
||||
fn_maybe_err(tcx, item.ident.span, abi);
|
||||
match item.kind {
|
||||
hir::TraitItemKind::Fn(ref sig, _) => {
|
||||
let abi = sig.header.abi;
|
||||
fn_maybe_err(tcx, item.ident.span, abi);
|
||||
}
|
||||
hir::TraitItemKind::Type(.., Some(_default)) => {
|
||||
let item_def_id = tcx.hir().local_def_id(item.hir_id).to_def_id();
|
||||
let assoc_item = tcx.associated_item(item_def_id);
|
||||
let trait_substs =
|
||||
InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
|
||||
let _: Result<_, rustc_errors::ErrorReported> = check_type_bounds(
|
||||
tcx,
|
||||
assoc_item,
|
||||
assoc_item,
|
||||
item.span,
|
||||
ty::TraitRef { def_id: def_id.to_def_id(), substs: trait_substs },
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
|
||||
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
|
||||
use rustc_infer::traits::util;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::subst::{InternalSubsts, Subst};
|
||||
@ -327,7 +328,7 @@ fn compare_predicate_entailment<'tcx>(
|
||||
// Finally, resolve all regions. This catches wily misuses of
|
||||
// lifetime parameters.
|
||||
let fcx = FnCtxt::new(&inh, param_env, impl_m_hir_id);
|
||||
fcx.regionck_item(impl_m_hir_id, impl_m_span, &[]);
|
||||
fcx.regionck_item(impl_m_hir_id, impl_m_span, trait_sig.inputs_and_output);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
@ -1052,7 +1053,7 @@ crate fn compare_ty_impl<'tcx>(
|
||||
|
||||
compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref)?;
|
||||
|
||||
compare_projection_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
|
||||
check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
|
||||
})();
|
||||
}
|
||||
|
||||
@ -1170,20 +1171,13 @@ fn compare_type_predicate_entailment<'tcx>(
|
||||
/// For default associated types the normalization is not possible (the value
|
||||
/// from the impl could be overridden). We also can't normalize generic
|
||||
/// associated types (yet) because they contain bound parameters.
|
||||
fn compare_projection_bounds<'tcx>(
|
||||
pub fn check_type_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ty: &ty::AssocItem,
|
||||
impl_ty: &ty::AssocItem,
|
||||
impl_ty_span: Span,
|
||||
impl_trait_ref: ty::TraitRef<'tcx>,
|
||||
) -> Result<(), ErrorReported> {
|
||||
let have_gats = tcx.features().generic_associated_types;
|
||||
if impl_ty.defaultness.is_final() && !have_gats {
|
||||
// For "final", non-generic associate type implementations, we
|
||||
// don't need this as described above.
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Given
|
||||
//
|
||||
// impl<A, B> Foo<u32> for (A, B) {
|
||||
@ -1211,16 +1205,27 @@ fn compare_projection_bounds<'tcx>(
|
||||
// ParamEnv for normalization specifically.
|
||||
let normalize_param_env = {
|
||||
let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
|
||||
predicates.push(
|
||||
ty::Binder::dummy(ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy {
|
||||
item_def_id: trait_ty.def_id,
|
||||
substs: rebased_substs,
|
||||
},
|
||||
ty: impl_ty_value,
|
||||
})
|
||||
.to_predicate(tcx),
|
||||
);
|
||||
match impl_ty_value.kind() {
|
||||
ty::Projection(proj)
|
||||
if proj.item_def_id == trait_ty.def_id && proj.substs == rebased_substs =>
|
||||
{
|
||||
// Don't include this predicate if the projected type is
|
||||
// exactly the same as the projection. This can occur in
|
||||
// (somewhat dubious) code like this:
|
||||
//
|
||||
// impl<T> X for T where T: X { type Y = <T as X>::Y; }
|
||||
}
|
||||
_ => predicates.push(
|
||||
ty::Binder::dummy(ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy {
|
||||
item_def_id: trait_ty.def_id,
|
||||
substs: rebased_substs,
|
||||
},
|
||||
ty: impl_ty_value,
|
||||
})
|
||||
.to_predicate(tcx),
|
||||
),
|
||||
};
|
||||
ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing)
|
||||
};
|
||||
|
||||
@ -1231,33 +1236,38 @@ fn compare_projection_bounds<'tcx>(
|
||||
|
||||
let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
|
||||
let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
|
||||
let cause = ObligationCause::new(
|
||||
impl_ty_span,
|
||||
impl_ty_hir_id,
|
||||
ObligationCauseCode::ItemObligation(trait_ty.def_id),
|
||||
);
|
||||
let mk_cause = |span| {
|
||||
ObligationCause::new(
|
||||
impl_ty_span,
|
||||
impl_ty_hir_id,
|
||||
ObligationCauseCode::BindingObligation(trait_ty.def_id, span),
|
||||
)
|
||||
};
|
||||
|
||||
let predicates = tcx.projection_predicates(trait_ty.def_id);
|
||||
debug!("compare_projection_bounds: projection_predicates={:?}", predicates);
|
||||
let obligations = tcx
|
||||
.explicit_item_bounds(trait_ty.def_id)
|
||||
.iter()
|
||||
.map(|&(bound, span)| {
|
||||
let concrete_ty_bound = bound.subst(tcx, rebased_substs);
|
||||
debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
|
||||
|
||||
for predicate in predicates {
|
||||
let concrete_ty_predicate = predicate.subst(tcx, rebased_substs);
|
||||
debug!("compare_projection_bounds: concrete predicate = {:?}", concrete_ty_predicate);
|
||||
traits::Obligation::new(mk_cause(span), param_env, concrete_ty_bound)
|
||||
})
|
||||
.collect();
|
||||
debug!("check_type_bounds: item_bounds={:?}", obligations);
|
||||
|
||||
for mut obligation in util::elaborate_obligations(tcx, obligations) {
|
||||
let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
|
||||
&mut selcx,
|
||||
normalize_param_env,
|
||||
normalize_cause.clone(),
|
||||
&concrete_ty_predicate,
|
||||
&obligation.predicate,
|
||||
);
|
||||
debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
|
||||
obligation.predicate = normalized_predicate;
|
||||
|
||||
inh.register_predicates(obligations);
|
||||
inh.register_predicate(traits::Obligation::new(
|
||||
cause.clone(),
|
||||
param_env,
|
||||
normalized_predicate,
|
||||
));
|
||||
inh.register_predicate(obligation);
|
||||
}
|
||||
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
@ -1270,7 +1280,11 @@ fn compare_projection_bounds<'tcx>(
|
||||
// Finally, resolve all regions. This catches wily misuses of
|
||||
// lifetime parameters.
|
||||
let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id);
|
||||
fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &[]);
|
||||
let implied_bounds = match impl_ty.container {
|
||||
ty::TraitContainer(_) => vec![],
|
||||
ty::ImplContainer(def_id) => fcx.impl_implied_bounds(def_id, impl_ty_span),
|
||||
};
|
||||
fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &implied_bounds);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
|
@ -420,6 +420,9 @@ fn check_associated_item(
|
||||
check_method_receiver(fcx, hir_sig, &item, self_ty);
|
||||
}
|
||||
ty::AssocKind::Type => {
|
||||
if let ty::AssocItemContainer::TraitContainer(_) = item.container {
|
||||
check_associated_type_bounds(fcx, item, span)
|
||||
}
|
||||
if item.defaultness.has_value() {
|
||||
let ty = fcx.tcx.type_of(item.def_id);
|
||||
let ty = fcx.normalize_associated_types_in(span, &ty);
|
||||
@ -571,7 +574,6 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
|
||||
|
||||
for_item(tcx, item).with_fcx(|fcx, _| {
|
||||
check_where_clauses(tcx, fcx, item.span, trait_def_id.to_def_id(), None);
|
||||
check_associated_type_defaults(fcx, trait_def_id.to_def_id());
|
||||
|
||||
vec![]
|
||||
});
|
||||
@ -581,96 +583,26 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
|
||||
///
|
||||
/// Assuming the defaults are used, check that all predicates (bounds on the
|
||||
/// assoc type and where clauses on the trait) hold.
|
||||
fn check_associated_type_defaults(fcx: &FnCtxt<'_, '_>, trait_def_id: DefId) {
|
||||
fn check_associated_type_bounds(fcx: &FnCtxt<'_, '_>, item: &ty::AssocItem, span: Span) {
|
||||
let tcx = fcx.tcx;
|
||||
let substs = InternalSubsts::identity_for_item(tcx, trait_def_id);
|
||||
|
||||
// For all assoc. types with defaults, build a map from
|
||||
// `<Self as Trait<...>>::Assoc` to the default type.
|
||||
let map = tcx
|
||||
.associated_items(trait_def_id)
|
||||
.in_definition_order()
|
||||
.filter_map(|item| {
|
||||
if item.kind == ty::AssocKind::Type && item.defaultness.has_value() {
|
||||
// `<Self as Trait<...>>::Assoc`
|
||||
let proj = ty::ProjectionTy { substs, item_def_id: item.def_id };
|
||||
let default_ty = tcx.type_of(item.def_id);
|
||||
debug!("assoc. type default mapping: {} -> {}", proj, default_ty);
|
||||
Some((proj, default_ty))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<FxHashMap<_, _>>();
|
||||
let bounds = tcx.explicit_item_bounds(item.def_id);
|
||||
|
||||
/// Replaces projections of associated types with their default types.
|
||||
///
|
||||
/// This does a "shallow substitution", meaning that defaults that refer to
|
||||
/// other defaulted assoc. types will still refer to the projection
|
||||
/// afterwards, not to the other default. For example:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// trait Tr {
|
||||
/// type A: Clone = Vec<Self::B>;
|
||||
/// type B = u8;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This will end up replacing the bound `Self::A: Clone` with
|
||||
/// `Vec<Self::B>: Clone`, not with `Vec<u8>: Clone`. If we did a deep
|
||||
/// substitution and ended up with the latter, the trait would be accepted.
|
||||
/// If an `impl` then replaced `B` with something that isn't `Clone`,
|
||||
/// suddenly the default for `A` is no longer valid. The shallow
|
||||
/// substitution forces the trait to add a `B: Clone` bound to be accepted,
|
||||
/// which means that an `impl` can replace any default without breaking
|
||||
/// others.
|
||||
///
|
||||
/// Note that this isn't needed for soundness: The defaults would still be
|
||||
/// checked in any impl that doesn't override them.
|
||||
struct DefaultNormalizer<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
map: FxHashMap<ty::ProjectionTy<'tcx>, Ty<'tcx>>,
|
||||
}
|
||||
debug!("check_associated_type_bounds: bounds={:?}", bounds);
|
||||
let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
|
||||
let normalized_bound = fcx.normalize_associated_types_in(span, &bound);
|
||||
traits::wf::predicate_obligations(
|
||||
fcx,
|
||||
fcx.param_env,
|
||||
fcx.body_id,
|
||||
normalized_bound,
|
||||
bound_span,
|
||||
)
|
||||
});
|
||||
|
||||
impl<'tcx> ty::fold::TypeFolder<'tcx> for DefaultNormalizer<'tcx> {
|
||||
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match t.kind() {
|
||||
ty::Projection(proj_ty) => {
|
||||
if let Some(default) = self.map.get(&proj_ty) {
|
||||
default
|
||||
} else {
|
||||
t.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
_ => t.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now take all predicates defined on the trait, replace any mention of
|
||||
// the assoc. types with their default, and prove them.
|
||||
// We only consider predicates that directly mention the assoc. type.
|
||||
let mut norm = DefaultNormalizer { tcx, map };
|
||||
let predicates = fcx.tcx.predicates_of(trait_def_id);
|
||||
for &(orig_pred, span) in predicates.predicates.iter() {
|
||||
let pred = orig_pred.fold_with(&mut norm);
|
||||
if pred != orig_pred {
|
||||
// Mentions one of the defaulted assoc. types
|
||||
debug!("default suitability check: proving predicate: {} -> {}", orig_pred, pred);
|
||||
let pred = fcx.normalize_associated_types_in(span, &pred);
|
||||
let cause = traits::ObligationCause::new(
|
||||
span,
|
||||
fcx.body_id,
|
||||
traits::ItemObligation(trait_def_id),
|
||||
);
|
||||
let obligation = traits::Obligation::new(cause, fcx.param_env, pred);
|
||||
|
||||
fcx.register_predicate(obligation);
|
||||
}
|
||||
for obligation in wf_obligations {
|
||||
debug!("next obligation cause: {:?}", obligation.cause);
|
||||
fcx.register_predicate(obligation);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1493,7 +1425,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec<Ty<'tcx>> {
|
||||
pub(super) fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec<Ty<'tcx>> {
|
||||
match self.tcx.impl_trait_ref(impl_def_id) {
|
||||
Some(ref trait_ref) => {
|
||||
// Trait impl: take implied bounds from all types that
|
||||
|
@ -50,6 +50,7 @@ use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi;
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
|
||||
|
||||
mod item_bounds;
|
||||
mod type_of;
|
||||
|
||||
struct OnlySelfBounds(bool);
|
||||
@ -68,12 +69,15 @@ pub fn provide(providers: &mut Providers) {
|
||||
*providers = Providers {
|
||||
opt_const_param_of: type_of::opt_const_param_of,
|
||||
type_of: type_of::type_of,
|
||||
item_bounds: item_bounds::item_bounds,
|
||||
explicit_item_bounds: item_bounds::explicit_item_bounds,
|
||||
generics_of,
|
||||
predicates_of,
|
||||
predicates_defined_on,
|
||||
projection_ty_from_predicates,
|
||||
explicit_predicates_of,
|
||||
super_predicates_of,
|
||||
trait_explicit_predicates_and_bounds,
|
||||
type_param_predicates,
|
||||
trait_def,
|
||||
adt_def,
|
||||
@ -700,6 +704,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::HirId) {
|
||||
hir::ItemKind::OpaqueTy(..) => {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
tcx.ensure().explicit_item_bounds(def_id);
|
||||
}
|
||||
hir::ItemKind::TyAlias(..)
|
||||
| hir::ItemKind::Static(..)
|
||||
@ -708,8 +713,10 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::HirId) {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
if let hir::ItemKind::Fn(..) = it.kind {
|
||||
tcx.ensure().fn_sig(def_id);
|
||||
match it.kind {
|
||||
hir::ItemKind::Fn(..) => tcx.ensure().fn_sig(def_id),
|
||||
hir::ItemKind::OpaqueTy(..) => tcx.ensure().item_bounds(def_id),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -730,15 +737,25 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::HirId) {
|
||||
tcx.ensure().type_of(def_id);
|
||||
}
|
||||
|
||||
hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(_, Some(_)) => {
|
||||
hir::TraitItemKind::Const(..) => {
|
||||
tcx.ensure().type_of(def_id);
|
||||
// Account for `const C: _;` and `type T = _;`.
|
||||
// Account for `const C: _;`.
|
||||
let mut visitor = PlaceholderHirTyCollector::default();
|
||||
visitor.visit_trait_item(trait_item);
|
||||
placeholder_type_error(tcx, None, &[], visitor.0, false);
|
||||
}
|
||||
|
||||
hir::TraitItemKind::Type(_, Some(_)) => {
|
||||
tcx.ensure().item_bounds(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
// Account for `type T = _;`.
|
||||
let mut visitor = PlaceholderHirTyCollector::default();
|
||||
visitor.visit_trait_item(trait_item);
|
||||
placeholder_type_error(tcx, None, &[], visitor.0, false);
|
||||
}
|
||||
|
||||
hir::TraitItemKind::Type(_, None) => {
|
||||
tcx.ensure().item_bounds(def_id);
|
||||
// #74612: Visit and try to find bad placeholders
|
||||
// even if there is no concrete type.
|
||||
let mut visitor = PlaceholderHirTyCollector::default();
|
||||
@ -1716,7 +1733,7 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
|
||||
|
||||
/// Returns a list of user-specified type predicates for the definition with ID `def_id`.
|
||||
/// N.B., this does not include any implied/inferred constraints.
|
||||
fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
|
||||
fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
|
||||
use rustc_hir::*;
|
||||
|
||||
debug!("explicit_predicates_of(def_id={:?})", def_id);
|
||||
@ -1726,7 +1743,6 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
|
||||
|
||||
let mut is_trait = None;
|
||||
let mut is_default_impl_trait = None;
|
||||
let mut is_trait_associated_type = None;
|
||||
|
||||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
let constness = icx.default_constness_for_trait_bounds();
|
||||
@ -1739,12 +1755,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
|
||||
let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
|
||||
|
||||
let ast_generics = match node {
|
||||
Node::TraitItem(item) => {
|
||||
if let hir::TraitItemKind::Type(bounds, _) = item.kind {
|
||||
is_trait_associated_type = Some((bounds, item.span));
|
||||
}
|
||||
&item.generics
|
||||
}
|
||||
Node::TraitItem(item) => &item.generics,
|
||||
|
||||
Node::ImplItem(item) => &item.generics,
|
||||
|
||||
@ -1762,44 +1773,38 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
|
||||
| ItemKind::Struct(_, ref generics)
|
||||
| ItemKind::Union(_, ref generics) => generics,
|
||||
|
||||
ItemKind::Trait(_, _, ref generics, .., items) => {
|
||||
is_trait = Some((ty::TraitRef::identity(tcx, def_id), items));
|
||||
ItemKind::Trait(_, _, ref generics, ..) => {
|
||||
is_trait = Some(ty::TraitRef::identity(tcx, def_id));
|
||||
generics
|
||||
}
|
||||
ItemKind::TraitAlias(ref generics, _) => {
|
||||
is_trait = Some((ty::TraitRef::identity(tcx, def_id), &[]));
|
||||
is_trait = Some(ty::TraitRef::identity(tcx, def_id));
|
||||
generics
|
||||
}
|
||||
ItemKind::OpaqueTy(OpaqueTy {
|
||||
ref bounds,
|
||||
bounds: _,
|
||||
impl_trait_fn,
|
||||
ref generics,
|
||||
origin: _,
|
||||
}) => {
|
||||
let bounds_predicates = ty::print::with_no_queries(|| {
|
||||
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||
let opaque_ty = tcx.mk_opaque(def_id, substs);
|
||||
|
||||
// Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`.
|
||||
let bounds = AstConv::compute_bounds(
|
||||
&icx,
|
||||
opaque_ty,
|
||||
bounds,
|
||||
SizedByDefault::Yes,
|
||||
tcx.def_span(def_id),
|
||||
);
|
||||
|
||||
bounds.predicates(tcx, opaque_ty)
|
||||
});
|
||||
if impl_trait_fn.is_some() {
|
||||
// opaque types
|
||||
return ty::GenericPredicates {
|
||||
parent: None,
|
||||
predicates: tcx.arena.alloc_from_iter(bounds_predicates),
|
||||
};
|
||||
// return-position impl trait
|
||||
//
|
||||
// We don't inherit predicates from the parent here:
|
||||
// If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
|
||||
// then the return type is `f::<'static, T>::{{opaque}}`.
|
||||
//
|
||||
// If we inherited the predicates of `f` then we would
|
||||
// require that `T: 'static` to show that the return
|
||||
// type is well-formed.
|
||||
//
|
||||
// The only way to have something with this opaque type
|
||||
// is from the return type of the containing function,
|
||||
// which will ensure that the function's predicates
|
||||
// hold.
|
||||
return ty::GenericPredicates { parent: None, predicates: &[] };
|
||||
} else {
|
||||
// named opaque types
|
||||
predicates.extend(bounds_predicates);
|
||||
// type-alias impl trait
|
||||
generics
|
||||
}
|
||||
}
|
||||
@ -1825,7 +1830,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
|
||||
// and the explicit where-clauses, but to get the full set of predicates
|
||||
// on a trait we need to add in the supertrait bounds and bounds found on
|
||||
// associated types.
|
||||
if let Some((_trait_ref, _)) = is_trait {
|
||||
if let Some(_trait_ref) = is_trait {
|
||||
predicates.extend(tcx.super_predicates_of(def_id).predicates.iter().cloned());
|
||||
}
|
||||
|
||||
@ -1992,24 +1997,6 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
|
||||
}
|
||||
}
|
||||
|
||||
// Add predicates from associated type bounds (`type X: Bound`)
|
||||
if tcx.features().generic_associated_types {
|
||||
// New behavior: bounds declared on associate type are predicates of that
|
||||
// associated type. Not the default because it needs more testing.
|
||||
if let Some((bounds, span)) = is_trait_associated_type {
|
||||
let projection_ty =
|
||||
tcx.mk_projection(def_id, InternalSubsts::identity_for_item(tcx, def_id));
|
||||
|
||||
predicates.extend(associated_item_bounds(tcx, def_id, bounds, projection_ty, span))
|
||||
}
|
||||
} else if let Some((self_trait_ref, trait_items)) = is_trait {
|
||||
// Current behavior: bounds declared on associate type are predicates
|
||||
// of its parent trait.
|
||||
predicates.extend(trait_items.iter().flat_map(|trait_item_ref| {
|
||||
trait_associated_item_predicates(tcx, def_id, self_trait_ref, trait_item_ref)
|
||||
}))
|
||||
}
|
||||
|
||||
if tcx.features().const_evaluatable_checked {
|
||||
predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
|
||||
}
|
||||
@ -2131,6 +2118,69 @@ fn const_evaluatable_predicates_of<'tcx>(
|
||||
collector.preds
|
||||
}
|
||||
|
||||
fn trait_explicit_predicates_and_bounds(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: LocalDefId,
|
||||
) -> ty::GenericPredicates<'_> {
|
||||
assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
|
||||
gather_explicit_predicates_of(tcx, def_id.to_def_id())
|
||||
}
|
||||
|
||||
fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
|
||||
if let DefKind::Trait = tcx.def_kind(def_id) {
|
||||
// Remove bounds on associated types from the predicates, they will be
|
||||
// returned by `explicit_item_bounds`.
|
||||
let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
|
||||
let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||
|
||||
let is_assoc_item_ty = |ty: Ty<'_>| {
|
||||
// For a predicate from a where clause to become a bound on an
|
||||
// associated type:
|
||||
// * It must use the identity substs of the item.
|
||||
// * Since any generic parameters on the item are not in scope,
|
||||
// this means that the item is not a GAT, and its identity
|
||||
// substs are the same as the trait's.
|
||||
// * It must be an associated type for this trait (*not* a
|
||||
// supertrait).
|
||||
if let ty::Projection(projection) = ty.kind() {
|
||||
if projection.substs == trait_identity_substs
|
||||
&& tcx.associated_item(projection.item_def_id).container.id() == def_id
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
let predicates: Vec<_> = predicates_and_bounds
|
||||
.predicates
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|(pred, _)| match pred.skip_binders() {
|
||||
ty::PredicateAtom::Trait(tr, _) => !is_assoc_item_ty(tr.self_ty()),
|
||||
ty::PredicateAtom::Projection(proj) => {
|
||||
!is_assoc_item_ty(proj.projection_ty.self_ty())
|
||||
}
|
||||
ty::PredicateAtom::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
|
||||
_ => true,
|
||||
})
|
||||
.collect();
|
||||
if predicates.len() == predicates_and_bounds.predicates.len() {
|
||||
predicates_and_bounds
|
||||
} else {
|
||||
ty::GenericPredicates {
|
||||
parent: predicates_and_bounds.parent,
|
||||
predicates: tcx.arena.alloc_slice(&predicates),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gather_explicit_predicates_of(tcx, def_id)
|
||||
}
|
||||
}
|
||||
|
||||
fn projection_ty_from_predicates(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
key: (
|
||||
@ -2153,55 +2203,6 @@ fn projection_ty_from_predicates(
|
||||
projection_ty
|
||||
}
|
||||
|
||||
fn trait_associated_item_predicates(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
self_trait_ref: ty::TraitRef<'tcx>,
|
||||
trait_item_ref: &hir::TraitItemRef,
|
||||
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
||||
let trait_item = tcx.hir().trait_item(trait_item_ref.id);
|
||||
let item_def_id = tcx.hir().local_def_id(trait_item_ref.id.hir_id);
|
||||
let bounds = match trait_item.kind {
|
||||
hir::TraitItemKind::Type(ref bounds, _) => bounds,
|
||||
_ => return Vec::new(),
|
||||
};
|
||||
|
||||
if !tcx.generics_of(item_def_id).params.is_empty() {
|
||||
// For GATs the substs provided to the mk_projection call below are
|
||||
// wrong. We should emit a feature gate error if we get here so skip
|
||||
// this type.
|
||||
tcx.sess.delay_span_bug(trait_item.span, "gats used without feature gate");
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let assoc_ty = tcx.mk_projection(
|
||||
tcx.hir().local_def_id(trait_item.hir_id).to_def_id(),
|
||||
self_trait_ref.substs,
|
||||
);
|
||||
|
||||
associated_item_bounds(tcx, def_id, bounds, assoc_ty, trait_item.span)
|
||||
}
|
||||
|
||||
fn associated_item_bounds(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
bounds: &'tcx [hir::GenericBound<'tcx>],
|
||||
projection_ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
||||
let bounds = AstConv::compute_bounds(
|
||||
&ItemCtxt::new(tcx, def_id),
|
||||
projection_ty,
|
||||
bounds,
|
||||
SizedByDefault::Yes,
|
||||
span,
|
||||
);
|
||||
|
||||
let predicates = bounds.predicates(tcx, projection_ty);
|
||||
|
||||
predicates
|
||||
}
|
||||
|
||||
/// Converts a specific `GenericBound` from the AST into a set of
|
||||
/// predicates that apply to the self type. A vector is returned
|
||||
/// because this can be anywhere from zero predicates (`T: ?Sized` adds no
|
||||
|
111
compiler/rustc_typeck/src/collect/item_bounds.rs
Normal file
111
compiler/rustc_typeck/src/collect/item_bounds.rs
Normal file
@ -0,0 +1,111 @@
|
||||
use super::ItemCtxt;
|
||||
use crate::astconv::{AstConv, SizedByDefault};
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::traits::util;
|
||||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::Span;
|
||||
|
||||
/// For associated types we include both bounds written on the type
|
||||
/// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`.
|
||||
///
|
||||
/// Note that this filtering is done with the items identity substs to
|
||||
/// simplify checking that these bounds are met in impls. This means that
|
||||
/// a bound such as `for<'b> <Self as X<'b>>::U: Clone` can't be used, as in
|
||||
/// `hr-associated-type-bound-1.rs`.
|
||||
fn associated_type_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
assoc_item_def_id: DefId,
|
||||
bounds: &'tcx [hir::GenericBound<'tcx>],
|
||||
span: Span,
|
||||
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
|
||||
let item_ty = tcx.mk_projection(
|
||||
assoc_item_def_id,
|
||||
InternalSubsts::identity_for_item(tcx, assoc_item_def_id),
|
||||
);
|
||||
|
||||
let bounds = AstConv::compute_bounds(
|
||||
&ItemCtxt::new(tcx, assoc_item_def_id),
|
||||
item_ty,
|
||||
bounds,
|
||||
SizedByDefault::Yes,
|
||||
span,
|
||||
);
|
||||
|
||||
let trait_def_id = tcx.associated_item(assoc_item_def_id).container.id();
|
||||
let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
|
||||
|
||||
let bounds_from_parent =
|
||||
trait_predicates.predicates.iter().copied().filter(|(pred, _)| match pred.skip_binders() {
|
||||
ty::PredicateAtom::Trait(tr, _) => tr.self_ty() == item_ty,
|
||||
ty::PredicateAtom::Projection(proj) => proj.projection_ty.self_ty() == item_ty,
|
||||
ty::PredicateAtom::TypeOutlives(outlives) => outlives.0 == item_ty,
|
||||
_ => false,
|
||||
});
|
||||
|
||||
let all_bounds = tcx
|
||||
.arena
|
||||
.alloc_from_iter(bounds.predicates(tcx, item_ty).into_iter().chain(bounds_from_parent));
|
||||
debug!("associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id), all_bounds);
|
||||
all_bounds
|
||||
}
|
||||
|
||||
/// Opaque types don't inherit bounds from their parent: for return position
|
||||
/// impl trait it isn't possible to write a suitable predicate on the
|
||||
/// containing function and for type-alias impl trait we don't have a backwards
|
||||
/// compatibility issue.
|
||||
fn opaque_type_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
opaque_def_id: DefId,
|
||||
bounds: &'tcx [hir::GenericBound<'tcx>],
|
||||
span: Span,
|
||||
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
|
||||
let item_ty =
|
||||
tcx.mk_opaque(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id));
|
||||
|
||||
let bounds = ty::print::with_no_queries(|| {
|
||||
AstConv::compute_bounds(
|
||||
&ItemCtxt::new(tcx, opaque_def_id),
|
||||
item_ty,
|
||||
bounds,
|
||||
SizedByDefault::Yes,
|
||||
span,
|
||||
)
|
||||
});
|
||||
|
||||
let bounds = bounds.predicates(tcx, item_ty);
|
||||
debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);
|
||||
|
||||
tcx.arena.alloc_slice(&bounds)
|
||||
}
|
||||
|
||||
pub(super) fn explicit_item_bounds(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: DefId,
|
||||
) -> &'_ [(ty::Predicate<'_>, Span)] {
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
|
||||
match tcx.hir().get(hir_id) {
|
||||
hir::Node::TraitItem(hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Type(bounds, _),
|
||||
span,
|
||||
..
|
||||
}) => associated_type_bounds(tcx, def_id, bounds, *span),
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }),
|
||||
span,
|
||||
..
|
||||
}) => opaque_type_bounds(tcx, def_id, bounds, *span),
|
||||
_ => bug!("item_bounds called on {:?}", def_id),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List<ty::Predicate<'_>> {
|
||||
tcx.mk_predicates(
|
||||
util::elaborate_predicates(
|
||||
tcx,
|
||||
tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound),
|
||||
)
|
||||
.map(|obligation| obligation.predicate),
|
||||
)
|
||||
}
|
@ -337,6 +337,7 @@ fn check_predicates<'tcx>(
|
||||
infcx,
|
||||
tcx.param_env(impl1_def_id),
|
||||
tcx.hir().local_def_id_to_hir_id(impl1_def_id),
|
||||
0,
|
||||
arg,
|
||||
span,
|
||||
) {
|
||||
|
@ -21,7 +21,7 @@ use rustc_middle::bug;
|
||||
use rustc_middle::middle::resolve_lifetime as rl;
|
||||
use rustc_middle::middle::stability;
|
||||
use rustc_middle::ty::fold::TypeFolder;
|
||||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::subst::{InternalSubsts, Subst};
|
||||
use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt};
|
||||
use rustc_mir::const_eval::{is_const_fn, is_min_const_fn, is_unstable_const_fn};
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
@ -1268,13 +1268,10 @@ impl Clean<Item> for ty::AssocItem {
|
||||
ty::AssocKind::Type => {
|
||||
let my_name = self.ident.name.clean(cx);
|
||||
|
||||
if let ty::TraitContainer(did) = self.container {
|
||||
// When loading a cross-crate associated type, the bounds for this type
|
||||
// are actually located on the trait/impl itself, so we need to load
|
||||
// all of the generics from there and then look for bounds that are
|
||||
// applied to this associated type in question.
|
||||
let predicates = cx.tcx.explicit_predicates_of(did);
|
||||
let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
|
||||
if let ty::TraitContainer(_) = self.container {
|
||||
let bounds = cx.tcx.explicit_item_bounds(self.def_id);
|
||||
let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
|
||||
let generics = (cx.tcx.generics_of(self.def_id), predicates).clean(cx);
|
||||
let mut bounds = generics
|
||||
.where_predicates
|
||||
.iter()
|
||||
@ -1678,19 +1675,22 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
||||
|
||||
ty::Opaque(def_id, substs) => {
|
||||
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
|
||||
// by looking up the projections associated with the def_id.
|
||||
let predicates_of = cx.tcx.explicit_predicates_of(def_id);
|
||||
// by looking up the bounds associated with the def_id.
|
||||
let substs = cx.tcx.lift(&substs).expect("Opaque lift failed");
|
||||
let bounds = predicates_of.instantiate(cx.tcx, substs);
|
||||
let bounds = cx
|
||||
.tcx
|
||||
.explicit_item_bounds(def_id)
|
||||
.iter()
|
||||
.map(|(bound, _)| bound.subst(cx.tcx, substs))
|
||||
.collect::<Vec<_>>();
|
||||
let mut regions = vec![];
|
||||
let mut has_sized = false;
|
||||
let mut bounds = bounds
|
||||
.predicates
|
||||
.iter()
|
||||
.filter_map(|predicate| {
|
||||
.filter_map(|bound| {
|
||||
// Note: The substs of opaque types can contain unbound variables,
|
||||
// meaning that we have to use `ignore_quantifiers_with_unbound_vars` here.
|
||||
let trait_ref = match predicate.bound_atom(cx.tcx).skip_binder() {
|
||||
let trait_ref = match bound.bound_atom(cx.tcx).skip_binder() {
|
||||
ty::PredicateAtom::Trait(tr, _constness) => {
|
||||
ty::Binder::bind(tr.trait_ref)
|
||||
}
|
||||
@ -1711,11 +1711,10 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
||||
}
|
||||
|
||||
let bounds: Vec<_> = bounds
|
||||
.predicates
|
||||
.iter()
|
||||
.filter_map(|pred| {
|
||||
.filter_map(|bound| {
|
||||
if let ty::PredicateAtom::Projection(proj) =
|
||||
pred.bound_atom(cx.tcx).skip_binder()
|
||||
bound.bound_atom(cx.tcx).skip_binder()
|
||||
{
|
||||
if proj.projection_ty.trait_ref(cx.tcx)
|
||||
== trait_ref.skip_binder()
|
||||
@ -2067,13 +2066,10 @@ impl Clean<Item> for doctree::OpaqueTy<'_> {
|
||||
visibility: self.vis.clean(cx),
|
||||
stability: cx.stability(self.id).clean(cx),
|
||||
deprecation: cx.deprecation(self.id).clean(cx),
|
||||
inner: OpaqueTyItem(
|
||||
OpaqueTy {
|
||||
bounds: self.opaque_ty.bounds.clean(cx),
|
||||
generics: self.opaque_ty.generics.clean(cx),
|
||||
},
|
||||
false,
|
||||
),
|
||||
inner: OpaqueTyItem(OpaqueTy {
|
||||
bounds: self.opaque_ty.bounds.clean(cx),
|
||||
generics: self.opaque_ty.generics.clean(cx),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ pub enum ItemEnum {
|
||||
FunctionItem(Function),
|
||||
ModuleItem(Module),
|
||||
TypedefItem(Typedef, bool /* is associated type */),
|
||||
OpaqueTyItem(OpaqueTy, bool /* is associated type */),
|
||||
OpaqueTyItem(OpaqueTy),
|
||||
StaticItem(Static),
|
||||
ConstantItem(Constant),
|
||||
TraitItem(Trait),
|
||||
|
@ -1709,7 +1709,7 @@ fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer, cache: &Cache)
|
||||
clean::ConstantItem(ref c) => item_constant(buf, cx, item, c),
|
||||
clean::ForeignTypeItem => item_foreign_type(buf, cx, item, cache),
|
||||
clean::KeywordItem(_) => item_keyword(buf, cx, item),
|
||||
clean::OpaqueTyItem(ref e, _) => item_opaque_ty(buf, cx, item, e, cache),
|
||||
clean::OpaqueTyItem(ref e) => item_opaque_ty(buf, cx, item, e, cache),
|
||||
clean::TraitAliasItem(ref ta) => item_trait_alias(buf, cx, item, ta, cache),
|
||||
_ => {
|
||||
// We don't generate pages for any other type.
|
||||
|
@ -1,6 +1,9 @@
|
||||
// revisions: rpass cfail
|
||||
|
||||
trait Tr {
|
||||
trait Tr
|
||||
where
|
||||
(Self::Arr,): Sized,
|
||||
{
|
||||
type Arr;
|
||||
|
||||
const C: usize = 0;
|
||||
|
@ -69,7 +69,7 @@ fn test() -> Option<Box<u32>> {
|
||||
|
||||
bb5: {
|
||||
StorageDead(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
|
||||
_0 = <Option<Box<u32>> as Try>::from_error(move _8) -> [return: bb6, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
|
||||
_0 = <Option<Box<u32>> as Try>::from_error(move _8) -> [return: bb6, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-62289.rs:9:15: 9:20
|
||||
// + literal: Const { ty: fn(<std::option::Option<std::boxed::Box<u32>> as std::ops::Try>::Error) -> std::option::Option<std::boxed::Box<u32>> {<std::option::Option<std::boxed::Box<u32>> as std::ops::Try>::from_error}, val: Value(Scalar(<ZST>)) }
|
||||
|
@ -29,7 +29,7 @@
|
||||
scope 8 {
|
||||
- debug v => _8; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
+ debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
let mut _12: i32; // in scope 8 at $DIR/simplify-arm.rs:24:14: 24:15
|
||||
let mut _12: i32; // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
}
|
||||
scope 8 {
|
||||
debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
let mut _12: i32; // in scope 8 at $DIR/simplify-arm.rs:24:14: 24:15
|
||||
let mut _12: i32; // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
}
|
||||
scope 8 {
|
||||
debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:14: 8:15
|
||||
let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@
|
||||
scope 8 {
|
||||
- debug v => _8; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
+ debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:14: 8:15
|
||||
let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i
|
||||
}
|
||||
scope 8 {
|
||||
debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:14: 8:15
|
||||
let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
// Check that `where Self::Output: Copy` is turned into a bound on `Op::Output`.
|
||||
|
||||
//check-pass
|
||||
|
||||
trait Op
|
||||
where
|
||||
Self::Output: Copy,
|
||||
{
|
||||
type Output;
|
||||
}
|
||||
|
||||
fn duplicate<T: Op>(x: T::Output) -> (T::Output, T::Output) {
|
||||
(x, x)
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -12,7 +12,9 @@
|
||||
|
||||
fn main() {}
|
||||
|
||||
trait Bar { type Assoc; }
|
||||
trait Bar {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
trait Thing {
|
||||
type Out;
|
||||
@ -20,11 +22,14 @@ trait Thing {
|
||||
}
|
||||
|
||||
struct AssocNoCopy;
|
||||
impl Bar for AssocNoCopy { type Assoc = String; }
|
||||
impl Bar for AssocNoCopy {
|
||||
type Assoc = String;
|
||||
}
|
||||
|
||||
impl Thing for AssocNoCopy {
|
||||
type Out = Box<dyn Bar<Assoc: Copy>>;
|
||||
//~^ ERROR the trait bound `String: Copy` is not satisfied
|
||||
//~| ERROR the trait bound `String: Copy` is not satisfied
|
||||
|
||||
fn func() -> Self::Out {
|
||||
Box::new(AssocNoCopy)
|
||||
|
@ -1,11 +1,15 @@
|
||||
error[E0277]: the trait bound `String: Copy` is not satisfied
|
||||
--> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:26:28
|
||||
--> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:30:28
|
||||
|
|
||||
LL | type Out = Box<dyn Bar<Assoc: Copy>>;
|
||||
| ^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
|
||||
|
|
||||
= note: the return type of a function must have a statically known size
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0277]: the trait bound `String: Copy` is not satisfied
|
||||
--> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:30:28
|
||||
|
|
||||
LL | type Out = Box<dyn Bar<Assoc: Copy>>;
|
||||
| ^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
@ -6,40 +6,49 @@
|
||||
use std::fmt::Debug;
|
||||
use std::iter::Once;
|
||||
|
||||
trait Lam<Binder> { type App; }
|
||||
trait Lam<Binder> {
|
||||
type App;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct L1;
|
||||
impl<'a> Lam<&'a u8> for L1 { type App = u8; }
|
||||
impl<'a> Lam<&'a u8> for L1 {
|
||||
type App = u8;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct L2;
|
||||
impl<'a, 'b> Lam<&'a &'b u8> for L2 { type App = u8; }
|
||||
impl<'a, 'b> Lam<&'a &'b u8> for L2 {
|
||||
type App = u8;
|
||||
}
|
||||
|
||||
trait Case1 {
|
||||
type C: Clone + Iterator<Item:
|
||||
Send + Iterator<Item:
|
||||
for<'a> Lam<&'a u8, App:
|
||||
Debug
|
||||
>
|
||||
> + Sync>;
|
||||
type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
|
||||
//~^ ERROR `<<Self as Case1>::C as Iterator>::Item` is not an iterator
|
||||
//~| ERROR `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
|
||||
//~| ERROR `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
|
||||
}
|
||||
|
||||
pub struct S1;
|
||||
impl Case1 for S1 {
|
||||
//~^ ERROR `<L1 as Lam<&'a u8>>::App` doesn't implement `Debug` [E0277]
|
||||
type C = Once<Once<L1>>;
|
||||
}
|
||||
|
||||
fn assume_case1<T: Case1>() {
|
||||
//~^ ERROR `<_ as Lam<&'a u8>>::App` doesn't implement `Debug` [E0277]
|
||||
//~| ERROR `<<T as Case1>::C as Iterator>::Item` is not an iterator [E0277]
|
||||
//~| ERROR `<<T as Case1>::C as Iterator>::Item` cannot be sent between threads safely [E0277]
|
||||
//~| ERROR `<<T as Case1>::C as Iterator>::Item` cannot be shared between threads safely [E0277]
|
||||
fn assert_a<_0, A>() where A: Iterator<Item = _0>, _0: Debug {}
|
||||
fn assert_a<_0, A>()
|
||||
where
|
||||
A: Iterator<Item = _0>,
|
||||
_0: Debug,
|
||||
{
|
||||
}
|
||||
assert_a::<_, T::A>();
|
||||
|
||||
fn assert_b<_0, B>() where B: Iterator<Item = _0>, _0: 'static {}
|
||||
fn assert_b<_0, B>()
|
||||
where
|
||||
B: Iterator<Item = _0>,
|
||||
_0: 'static,
|
||||
{
|
||||
}
|
||||
assert_b::<_, T::B>();
|
||||
|
||||
fn assert_c<_0, _1, _2, C>()
|
||||
@ -48,7 +57,8 @@ fn assume_case1<T: Case1>() {
|
||||
_2: Send + Iterator<Item = _1>,
|
||||
_1: for<'a> Lam<&'a u8, App = _0>,
|
||||
_0: Debug,
|
||||
{}
|
||||
{
|
||||
}
|
||||
assert_c::<_, _, _, T::C>();
|
||||
}
|
||||
|
||||
|
@ -1,79 +1,49 @@
|
||||
error[E0277]: `<L1 as Lam<&'a u8>>::App` doesn't implement `Debug`
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:29:6
|
||||
error[E0277]: `<<Self as Case1>::C as Iterator>::Item` is not an iterator
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:26:5
|
||||
|
|
||||
LL | trait Case1 {
|
||||
| ----- required by a bound in this
|
||||
...
|
||||
LL | Debug
|
||||
| ----- required by this bound in `Case1`
|
||||
...
|
||||
LL | impl Case1 for S1 {
|
||||
| ^^^^^ `<L1 as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
||||
LL | type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<<Self as Case1>::C as Iterator>::Item` is not an iterator
|
||||
|
|
||||
= help: the trait `for<'a> Debug` is not implemented for `<L1 as Lam<&'a u8>>::App`
|
||||
|
||||
error[E0277]: `<<T as Case1>::C as Iterator>::Item` is not an iterator
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:34:20
|
||||
|
|
||||
LL | fn assume_case1<T: Case1>() {
|
||||
| ^^^^^ `<<T as Case1>::C as Iterator>::Item` is not an iterator
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `<<T as Case1>::C as Iterator>::Item`
|
||||
= help: the trait `Iterator` is not implemented for `<<Self as Case1>::C as Iterator>::Item`
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | fn assume_case1<T: Case1>() where <<T as Case1>::C as Iterator>::Item: Iterator {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Iterator {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: `<<T as Case1>::C as Iterator>::Item` cannot be sent between threads safely
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:34:20
|
||||
error[E0277]: `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:26:36
|
||||
|
|
||||
LL | trait Case1 {
|
||||
| ----- required by a bound in this
|
||||
LL | type C: Clone + Iterator<Item:
|
||||
LL | Send + Iterator<Item:
|
||||
| ---- required by this bound in `Case1`
|
||||
...
|
||||
LL | fn assume_case1<T: Case1>() {
|
||||
| ^^^^^ `<<T as Case1>::C as Iterator>::Item` cannot be sent between threads safely
|
||||
LL | type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
|
||||
| ^^^^ `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
|
||||
|
|
||||
::: $SRC_DIR/core/src/marker.rs:LL:COL
|
||||
|
|
||||
= help: the trait `Send` is not implemented for `<<T as Case1>::C as Iterator>::Item`
|
||||
LL | pub unsafe auto trait Send {
|
||||
| -------------------------- required by this bound in `Send`
|
||||
|
|
||||
= help: the trait `Send` is not implemented for `<<Self as Case1>::C as Iterator>::Item`
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | fn assume_case1<T: Case1>() where <<T as Case1>::C as Iterator>::Item: Send {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Send {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: `<<T as Case1>::C as Iterator>::Item` cannot be shared between threads safely
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:34:20
|
||||
error[E0277]: `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:26:93
|
||||
|
|
||||
LL | trait Case1 {
|
||||
| ----- required by a bound in this
|
||||
...
|
||||
LL | > + Sync>;
|
||||
| ---- required by this bound in `Case1`
|
||||
...
|
||||
LL | fn assume_case1<T: Case1>() {
|
||||
| ^^^^^ `<<T as Case1>::C as Iterator>::Item` cannot be shared between threads safely
|
||||
LL | type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
|
||||
| ^^^^ `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
|
||||
|
|
||||
::: $SRC_DIR/core/src/marker.rs:LL:COL
|
||||
|
|
||||
= help: the trait `Sync` is not implemented for `<<T as Case1>::C as Iterator>::Item`
|
||||
LL | pub unsafe auto trait Sync {
|
||||
| -------------------------- required by this bound in `Sync`
|
||||
|
|
||||
= help: the trait `Sync` is not implemented for `<<Self as Case1>::C as Iterator>::Item`
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | fn assume_case1<T: Case1>() where <<T as Case1>::C as Iterator>::Item: Sync {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Sync {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `Debug`
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:34:20
|
||||
|
|
||||
LL | trait Case1 {
|
||||
| ----- required by a bound in this
|
||||
...
|
||||
LL | Debug
|
||||
| ----- required by this bound in `Case1`
|
||||
...
|
||||
LL | fn assume_case1<T: Case1>() {
|
||||
| ^^^^^ `<_ as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
||||
|
|
||||
= help: the trait `for<'a> Debug` is not implemented for `<_ as Lam<&'a u8>>::App`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
@ -1,5 +1,3 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
@ -18,6 +16,7 @@ impl<'a, 'b> Lam<&'a &'b u8> for L2 { type App = u8; }
|
||||
|
||||
trait Case1 {
|
||||
type A: Iterator<Item: Debug>;
|
||||
//~^ ERROR `<<Self as Case1>::A as Iterator>::Item` doesn't implement `Debug`
|
||||
|
||||
type B: Iterator<Item: 'static>;
|
||||
}
|
||||
@ -30,7 +29,11 @@ impl Case1 for S1 {
|
||||
|
||||
// Ensure we don't have opaque `impl Trait` desugaring:
|
||||
|
||||
// What is this supposed to mean? Rustc currently lowers `: Default` in the
|
||||
// bounds of `Out`, but trait selection can't find the bound since it applies
|
||||
// to a type other than `Self::Out`.
|
||||
pub trait Foo { type Out: Baz<Assoc: Default>; }
|
||||
//~^ ERROR trait bound `<<Self as Foo>::Out as Baz>::Assoc: Default` is not satisfied
|
||||
pub trait Baz { type Assoc; }
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -0,0 +1,36 @@
|
||||
error[E0277]: `<<Self as Case1>::A as Iterator>::Item` doesn't implement `Debug`
|
||||
--> $DIR/bounds-on-assoc-in-trait.rs:18:28
|
||||
|
|
||||
LL | type A: Iterator<Item: Debug>;
|
||||
| ^^^^^ `<<Self as Case1>::A as Iterator>::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
||||
|
|
||||
::: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
|
||||
|
|
||||
LL | pub trait Debug {
|
||||
| --------------- required by this bound in `Debug`
|
||||
|
|
||||
= help: the trait `Debug` is not implemented for `<<Self as Case1>::A as Iterator>::Item`
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | trait Case1 where <<Self as Case1>::A as Iterator>::Item: Debug {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `<<Self as Foo>::Out as Baz>::Assoc: Default` is not satisfied
|
||||
--> $DIR/bounds-on-assoc-in-trait.rs:35:38
|
||||
|
|
||||
LL | pub trait Foo { type Out: Baz<Assoc: Default>; }
|
||||
| ^^^^^^^ the trait `Default` is not implemented for `<<Self as Foo>::Out as Baz>::Assoc`
|
||||
|
|
||||
::: $SRC_DIR/core/src/default.rs:LL:COL
|
||||
|
|
||||
LL | pub trait Default: Sized {
|
||||
| ------------------------ required by this bound in `Default`
|
||||
|
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | pub trait Foo where <<Self as Foo>::Out as Baz>::Assoc: Default { type Out: Baz<Assoc: Default>; }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -511,30 +511,6 @@ LL | trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {}
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:145:43
|
||||
|
|
||||
LL | trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:147:43
|
||||
|
|
||||
LL | trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:149:46
|
||||
|
|
||||
LL | trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; }
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:152:40
|
||||
|
|
||||
@ -559,6 +535,30 @@ LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:145:43
|
||||
|
|
||||
LL | trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:147:43
|
||||
|
|
||||
LL | trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:149:46
|
||||
|
|
||||
LL | trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; }
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error: aborting due to 69 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0719`.
|
||||
|
@ -0,0 +1,25 @@
|
||||
// Make sure that we normalize bounds on associated types before checking them
|
||||
// as candidates.
|
||||
|
||||
// check-pass
|
||||
|
||||
trait Mul<T> {
|
||||
type Output;
|
||||
}
|
||||
|
||||
trait Matrix: Mul<<Self as Matrix>::Row, Output = ()> {
|
||||
type Row;
|
||||
|
||||
type Transpose: Matrix<Row = Self::Row>;
|
||||
}
|
||||
|
||||
fn is_mul<S, T: Mul<S, Output = ()>>() {}
|
||||
|
||||
fn f<T: Matrix>() {
|
||||
// The unnormalized bound on `T::Transpose` is
|
||||
// `Mul<<T::Transpose as Matrix>::Row` which has to be normalized to be
|
||||
// equal to `T::Row`.
|
||||
is_mul::<T::Row, T::Transpose>();
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,23 @@
|
||||
// Make sure that if there are multiple applicable bounds on a projection, we
|
||||
// consider them ambiguous. In this test we are initially trying to solve
|
||||
// `Self::Repr: From<_>`, which is ambiguous until we later infer `_` to
|
||||
// `{integer}`.
|
||||
|
||||
// check-pass
|
||||
|
||||
trait PrimeField: Sized {
|
||||
type Repr: From<u64> + From<Self>;
|
||||
type Repr2: From<Self> + From<u64>;
|
||||
|
||||
fn method() {
|
||||
Self::Repr::from(10);
|
||||
Self::Repr2::from(10);
|
||||
}
|
||||
}
|
||||
|
||||
fn function<T: PrimeField>() {
|
||||
T::Repr::from(10);
|
||||
T::Repr2::from(10);
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,16 @@
|
||||
// Check that if we have multiple applicable projection bounds we pick one (for
|
||||
// backwards compatibility reasons).
|
||||
|
||||
// check-pass
|
||||
use std::ops::Mul;
|
||||
|
||||
trait A {
|
||||
type V;
|
||||
type U: Mul<Self::V, Output = ()> + Mul<(), Output = ()>;
|
||||
}
|
||||
|
||||
fn g<T: A<V = ()>>() {
|
||||
let y: <T::U as Mul<()>>::Output = ();
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -1,11 +1,14 @@
|
||||
error[E0284]: type annotations needed
|
||||
error[E0283]: type annotations needed
|
||||
--> $DIR/associated-types-unconstrained.rs:14:20
|
||||
|
|
||||
LL | fn bar() -> isize;
|
||||
| ------------------ required by `Foo::bar`
|
||||
...
|
||||
LL | let x: isize = Foo::bar();
|
||||
| ^^^^^^^^ cannot infer type
|
||||
|
|
||||
= note: cannot satisfy `<_ as Foo>::A == _`
|
||||
= note: cannot satisfy `_: Foo`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0284`.
|
||||
For more information about this error, try `rustc --explain E0283`.
|
||||
|
@ -6,11 +6,8 @@ trait Tr {
|
||||
type B = Self::A;
|
||||
}
|
||||
|
||||
// ...but is an error in any impl that doesn't override at least one of the defaults
|
||||
impl Tr for () {}
|
||||
//~^ ERROR overflow evaluating the requirement
|
||||
|
||||
// As soon as at least one is redefined, it works:
|
||||
impl Tr for u8 {
|
||||
type A = u8;
|
||||
}
|
||||
@ -24,16 +21,14 @@ impl Tr for u32 {
|
||||
type B = u8;
|
||||
}
|
||||
|
||||
// ...but only if this actually breaks the cycle
|
||||
// ...but not in an impl that redefines one of the types.
|
||||
impl Tr for bool {
|
||||
//~^ ERROR type mismatch resolving `<bool as Tr>::B == _`
|
||||
type A = Box<Self::B>;
|
||||
//~^ ERROR type mismatch resolving `<bool as Tr>::B == _`
|
||||
}
|
||||
// (the error is shown twice for some reason)
|
||||
|
||||
impl Tr for usize {
|
||||
//~^ ERROR type mismatch resolving `<usize as Tr>::B == _`
|
||||
type B = &'static Self::A;
|
||||
//~^ ERROR type mismatch resolving `<usize as Tr>::A == _`
|
||||
}
|
||||
|
@ -1,34 +1,15 @@
|
||||
error[E0275]: overflow evaluating the requirement `<() as Tr>::B == _`
|
||||
--> $DIR/defaults-cyclic-fail-1.rs:10:6
|
||||
|
|
||||
LL | impl Tr for () {}
|
||||
| ^^
|
||||
|
||||
error[E0271]: type mismatch resolving `<bool as Tr>::B == _`
|
||||
--> $DIR/defaults-cyclic-fail-1.rs:28:6
|
||||
|
|
||||
LL | impl Tr for bool {
|
||||
| ^^ cyclic type of infinite size
|
||||
|
||||
error[E0271]: type mismatch resolving `<usize as Tr>::B == _`
|
||||
--> $DIR/defaults-cyclic-fail-1.rs:35:6
|
||||
|
|
||||
LL | impl Tr for usize {
|
||||
| ^^ cyclic type of infinite size
|
||||
|
||||
error[E0271]: type mismatch resolving `<bool as Tr>::B == _`
|
||||
--> $DIR/defaults-cyclic-fail-1.rs:30:5
|
||||
--> $DIR/defaults-cyclic-fail-1.rs:26:5
|
||||
|
|
||||
LL | type A = Box<Self::B>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
|
||||
|
||||
error[E0271]: type mismatch resolving `<usize as Tr>::A == _`
|
||||
--> $DIR/defaults-cyclic-fail-1.rs:37:5
|
||||
--> $DIR/defaults-cyclic-fail-1.rs:32:5
|
||||
|
|
||||
LL | type B = &'static Self::A;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0271, E0275.
|
||||
For more information about an error, try `rustc --explain E0271`.
|
||||
For more information about this error, try `rustc --explain E0271`.
|
||||
|
@ -8,11 +8,8 @@ trait Tr {
|
||||
type B = Box<Self::A>;
|
||||
}
|
||||
|
||||
// ...but is an error in any impl that doesn't override at least one of the defaults
|
||||
impl Tr for () {}
|
||||
//~^ ERROR type mismatch resolving `<() as Tr>::B == _`
|
||||
|
||||
// As soon as at least one is redefined, it works:
|
||||
impl Tr for u8 {
|
||||
type A = u8;
|
||||
}
|
||||
@ -26,16 +23,13 @@ impl Tr for u32 {
|
||||
type B = u8;
|
||||
}
|
||||
|
||||
// ...but only if this actually breaks the cycle
|
||||
impl Tr for bool {
|
||||
//~^ ERROR type mismatch resolving `<bool as Tr>::B == _`
|
||||
type A = Box<Self::B>;
|
||||
//~^ ERROR type mismatch resolving `<bool as Tr>::B == _`
|
||||
}
|
||||
// (the error is shown twice for some reason)
|
||||
|
||||
impl Tr for usize {
|
||||
//~^ ERROR type mismatch resolving `<usize as Tr>::B == _`
|
||||
type B = &'static Self::A;
|
||||
//~^ ERROR type mismatch resolving `<usize as Tr>::A == _`
|
||||
}
|
||||
|
@ -1,33 +1,15 @@
|
||||
error[E0271]: type mismatch resolving `<() as Tr>::B == _`
|
||||
--> $DIR/defaults-cyclic-fail-2.rs:12:6
|
||||
|
|
||||
LL | impl Tr for () {}
|
||||
| ^^ cyclic type of infinite size
|
||||
|
||||
error[E0271]: type mismatch resolving `<bool as Tr>::B == _`
|
||||
--> $DIR/defaults-cyclic-fail-2.rs:30:6
|
||||
|
|
||||
LL | impl Tr for bool {
|
||||
| ^^ cyclic type of infinite size
|
||||
|
||||
error[E0271]: type mismatch resolving `<usize as Tr>::B == _`
|
||||
--> $DIR/defaults-cyclic-fail-2.rs:37:6
|
||||
|
|
||||
LL | impl Tr for usize {
|
||||
| ^^ cyclic type of infinite size
|
||||
|
||||
error[E0271]: type mismatch resolving `<bool as Tr>::B == _`
|
||||
--> $DIR/defaults-cyclic-fail-2.rs:32:5
|
||||
--> $DIR/defaults-cyclic-fail-2.rs:27:5
|
||||
|
|
||||
LL | type A = Box<Self::B>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
|
||||
|
||||
error[E0271]: type mismatch resolving `<usize as Tr>::A == _`
|
||||
--> $DIR/defaults-cyclic-fail-2.rs:39:5
|
||||
--> $DIR/defaults-cyclic-fail-2.rs:33:5
|
||||
|
|
||||
LL | type B = &'static Self::A;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0271`.
|
||||
|
@ -1,10 +1,8 @@
|
||||
//! Checks that associated type defaults are properly validated.
|
||||
//!
|
||||
//! This means:
|
||||
//! * Default types are wfchecked
|
||||
//! * Default types are checked against where clauses on the assoc. type
|
||||
//! (eg. `type Assoc: Clone = NotClone`), and also against where clauses on
|
||||
//! the trait itself when possible
|
||||
//! (eg. `type Assoc: Clone = NotClone`)
|
||||
|
||||
#![feature(associated_type_defaults)]
|
||||
|
||||
@ -17,15 +15,12 @@ trait Tr {
|
||||
}
|
||||
|
||||
// Where-clauses defined on the trait must also be considered
|
||||
trait Tr2 where Self::Ty: Clone {
|
||||
//~^ ERROR the trait bound `NotClone: Clone` is not satisfied
|
||||
trait Tr2
|
||||
where
|
||||
Self::Ty: Clone,
|
||||
{
|
||||
type Ty = NotClone;
|
||||
}
|
||||
|
||||
// Independent of where-clauses (there are none here), default types must always be wf
|
||||
trait Tr3 {
|
||||
type Ty = Vec<[u8]>;
|
||||
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
|
||||
//~^ ERROR the trait bound `NotClone: Clone` is not satisfied
|
||||
}
|
||||
|
||||
// Involved type parameters must fulfill all bounds required by defaults that mention them
|
||||
@ -43,7 +38,7 @@ trait Bar: Sized {
|
||||
trait IsU8<T> {}
|
||||
impl<T> IsU8<u8> for T {}
|
||||
|
||||
// Test that mentioning the assoc. type inside where clauses works
|
||||
// Test that mentioning the assoc. type inside where clauses is not allowed
|
||||
trait C where
|
||||
Vec<Self::Assoc>: Clone,
|
||||
Self::Assoc: IsU8<Self::Assoc>,
|
||||
@ -55,13 +50,11 @@ trait C where
|
||||
// Test that we get all expected errors if that default is unsuitable
|
||||
trait D where
|
||||
Vec<Self::Assoc>: Clone,
|
||||
//~^ ERROR the trait bound `NotClone: Clone` is not satisfied
|
||||
Self::Assoc: IsU8<Self::Assoc>,
|
||||
//~^ ERROR the trait bound `NotClone: IsU8<NotClone>` is not satisfied
|
||||
bool: IsU8<Self::Assoc>,
|
||||
//~^ ERROR the trait bound `bool: IsU8<NotClone>` is not satisfied
|
||||
{
|
||||
type Assoc = NotClone;
|
||||
//~^ ERROR the trait bound `NotClone: IsU8<NotClone>` is not satisfied
|
||||
}
|
||||
|
||||
// Test behavior of the check when defaults refer to other defaults:
|
||||
@ -85,18 +78,20 @@ trait Foo25<T: Clone> {
|
||||
|
||||
// Adding the `Baz: Clone` bound isn't enough since the default is type
|
||||
// parameter `T`, which also might not be `Clone`.
|
||||
trait Foo3<T> where
|
||||
trait Foo3<T>
|
||||
where
|
||||
Self::Bar: Clone,
|
||||
Self::Baz: Clone,
|
||||
//~^ ERROR the trait bound `T: Clone` is not satisfied
|
||||
{
|
||||
type Bar = Vec<Self::Baz>;
|
||||
type Baz = T;
|
||||
//~^ ERROR the trait bound `T: Clone` is not satisfied
|
||||
}
|
||||
|
||||
// This one finally works, with `Clone` bounds on all assoc. types and the type
|
||||
// parameter.
|
||||
trait Foo4<T> where
|
||||
trait Foo4<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
type Bar: Clone = Vec<Self::Baz>;
|
||||
|
@ -1,27 +1,32 @@
|
||||
error[E0277]: the trait bound `NotClone: Clone` is not satisfied
|
||||
--> $DIR/defaults-suitability.rs:15:14
|
||||
--> $DIR/defaults-suitability.rs:13:5
|
||||
|
|
||||
LL | trait Tr {
|
||||
| -------- required by `Tr`
|
||||
LL | type Ty: Clone = NotClone;
|
||||
| ^^^^^ the trait `Clone` is not implemented for `NotClone`
|
||||
| ^^^^^^^^^-----^^^^^^^^^^^^
|
||||
| | |
|
||||
| | required by this bound in `Tr::Ty`
|
||||
| the trait `Clone` is not implemented for `NotClone`
|
||||
|
||||
error[E0277]: the trait bound `NotClone: Clone` is not satisfied
|
||||
--> $DIR/defaults-suitability.rs:20:27
|
||||
--> $DIR/defaults-suitability.rs:22:5
|
||||
|
|
||||
LL | trait Tr2 where Self::Ty: Clone {
|
||||
| --------------------------^^^^^
|
||||
| | |
|
||||
| | the trait `Clone` is not implemented for `NotClone`
|
||||
| required by `Tr2`
|
||||
LL | Self::Ty: Clone,
|
||||
| ----- required by this bound in `Tr2::Ty`
|
||||
LL | {
|
||||
LL | type Ty = NotClone;
|
||||
| ^^^^^--^^^^^^^^^^^^
|
||||
| | |
|
||||
| | required by a bound in this
|
||||
| the trait `Clone` is not implemented for `NotClone`
|
||||
|
||||
error[E0277]: the trait bound `T: Clone` is not satisfied
|
||||
--> $DIR/defaults-suitability.rs:33:15
|
||||
--> $DIR/defaults-suitability.rs:28:5
|
||||
|
|
||||
LL | trait Foo<T> {
|
||||
| ------------ required by `Foo`
|
||||
LL | type Bar: Clone = Vec<T>;
|
||||
| ^^^^^ the trait `Clone` is not implemented for `T`
|
||||
| ^^^^^^^^^^-----^^^^^^^^^^
|
||||
| | |
|
||||
| | required by this bound in `Foo::Bar`
|
||||
| the trait `Clone` is not implemented for `T`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `Clone` for `Vec<T>`
|
||||
help: consider restricting type parameter `T`
|
||||
@ -30,64 +35,34 @@ LL | trait Foo<T: Clone> {
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `(): Foo<Self>` is not satisfied
|
||||
--> $DIR/defaults-suitability.rs:39:17
|
||||
--> $DIR/defaults-suitability.rs:34:5
|
||||
|
|
||||
LL | trait Bar: Sized {
|
||||
| ---------------- required by `Bar`
|
||||
LL | // `(): Foo<Self>` might hold for some possible impls but not all.
|
||||
LL | type Assoc: Foo<Self> = ();
|
||||
| ^^^^^^^^^ the trait `Foo<Self>` is not implemented for `()`
|
||||
| ^^^^^^^^^^^^---------^^^^^^
|
||||
| | |
|
||||
| | required by this bound in `Bar::Assoc`
|
||||
| the trait `Foo<Self>` is not implemented for `()`
|
||||
|
||||
error[E0277]: the trait bound `NotClone: IsU8<NotClone>` is not satisfied
|
||||
--> $DIR/defaults-suitability.rs:59:18
|
||||
--> $DIR/defaults-suitability.rs:56:5
|
||||
|
|
||||
LL | / trait D where
|
||||
LL | | Vec<Self::Assoc>: Clone,
|
||||
LL | |
|
||||
LL | | Self::Assoc: IsU8<Self::Assoc>,
|
||||
| | ^^^^^^^^^^^^^^^^^ the trait `IsU8<NotClone>` is not implemented for `NotClone`
|
||||
... |
|
||||
LL | | type Assoc = NotClone;
|
||||
LL | | }
|
||||
| |_- required by `D`
|
||||
|
||||
error[E0277]: the trait bound `bool: IsU8<NotClone>` is not satisfied
|
||||
--> $DIR/defaults-suitability.rs:61:11
|
||||
|
|
||||
LL | / trait D where
|
||||
LL | | Vec<Self::Assoc>: Clone,
|
||||
LL | |
|
||||
LL | | Self::Assoc: IsU8<Self::Assoc>,
|
||||
LL | |
|
||||
LL | | bool: IsU8<Self::Assoc>,
|
||||
| | ^^^^^^^^^^^^^^^^^ the trait `IsU8<NotClone>` is not implemented for `bool`
|
||||
... |
|
||||
LL | | type Assoc = NotClone;
|
||||
LL | | }
|
||||
| |_- required by `D`
|
||||
|
||||
error[E0277]: the trait bound `NotClone: Clone` is not satisfied
|
||||
--> $DIR/defaults-suitability.rs:57:23
|
||||
|
|
||||
LL | / trait D where
|
||||
LL | | Vec<Self::Assoc>: Clone,
|
||||
| | ^^^^^ the trait `Clone` is not implemented for `NotClone`
|
||||
LL | |
|
||||
LL | | Self::Assoc: IsU8<Self::Assoc>,
|
||||
... |
|
||||
LL | | type Assoc = NotClone;
|
||||
LL | | }
|
||||
| |_- required by `D`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `Clone` for `Vec<NotClone>`
|
||||
LL | Self::Assoc: IsU8<Self::Assoc>,
|
||||
| ----------------- required by this bound in `D::Assoc`
|
||||
...
|
||||
LL | type Assoc = NotClone;
|
||||
| ^^^^^-----^^^^^^^^^^^^
|
||||
| | |
|
||||
| | required by a bound in this
|
||||
| the trait `IsU8<NotClone>` is not implemented for `NotClone`
|
||||
|
||||
error[E0277]: the trait bound `<Self as Foo2<T>>::Baz: Clone` is not satisfied
|
||||
--> $DIR/defaults-suitability.rs:72:15
|
||||
--> $DIR/defaults-suitability.rs:65:5
|
||||
|
|
||||
LL | trait Foo2<T> {
|
||||
| ------------- required by `Foo2`
|
||||
LL | type Bar: Clone = Vec<Self::Baz>;
|
||||
| ^^^^^ the trait `Clone` is not implemented for `<Self as Foo2<T>>::Baz`
|
||||
| ^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^
|
||||
| | |
|
||||
| | required by this bound in `Foo2::Bar`
|
||||
| the trait `Clone` is not implemented for `<Self as Foo2<T>>::Baz`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `Clone` for `Vec<<Self as Foo2<T>>::Baz>`
|
||||
help: consider further restricting the associated type
|
||||
@ -96,12 +71,13 @@ LL | trait Foo2<T> where <Self as Foo2<T>>::Baz: Clone {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `<Self as Foo25<T>>::Baz: Clone` is not satisfied
|
||||
--> $DIR/defaults-suitability.rs:81:15
|
||||
--> $DIR/defaults-suitability.rs:74:5
|
||||
|
|
||||
LL | trait Foo25<T: Clone> {
|
||||
| --------------------- required by `Foo25`
|
||||
LL | type Bar: Clone = Vec<Self::Baz>;
|
||||
| ^^^^^ the trait `Clone` is not implemented for `<Self as Foo25<T>>::Baz`
|
||||
| ^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^
|
||||
| | |
|
||||
| | required by this bound in `Foo25::Bar`
|
||||
| the trait `Clone` is not implemented for `<Self as Foo25<T>>::Baz`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `Clone` for `Vec<<Self as Foo25<T>>::Baz>`
|
||||
help: consider further restricting the associated type
|
||||
@ -110,36 +86,22 @@ LL | trait Foo25<T: Clone> where <Self as Foo25<T>>::Baz: Clone {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `T: Clone` is not satisfied
|
||||
--> $DIR/defaults-suitability.rs:90:16
|
||||
--> $DIR/defaults-suitability.rs:87:5
|
||||
|
|
||||
LL | / trait Foo3<T> where
|
||||
LL | | Self::Bar: Clone,
|
||||
LL | | Self::Baz: Clone,
|
||||
| | ^^^^^ the trait `Clone` is not implemented for `T`
|
||||
LL | |
|
||||
... |
|
||||
LL | | type Baz = T;
|
||||
LL | | }
|
||||
| |_- required by `Foo3`
|
||||
LL | Self::Baz: Clone,
|
||||
| ----- required by this bound in `Foo3::Baz`
|
||||
...
|
||||
LL | type Baz = T;
|
||||
| ^^^^^---^^^^^
|
||||
| | |
|
||||
| | required by a bound in this
|
||||
| the trait `Clone` is not implemented for `T`
|
||||
|
|
||||
help: consider further restricting type parameter `T`
|
||||
|
|
||||
LL | Self::Baz: Clone, T: Clone
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||
--> $DIR/defaults-suitability.rs:27:5
|
||||
|
|
||||
LL | type Ty = Vec<[u8]>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
::: $SRC_DIR/alloc/src/vec.rs:LL:COL
|
||||
|
|
||||
LL | pub struct Vec<T> {
|
||||
| - required by this bound in `Vec`
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `[u8]`
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
@ -11,22 +11,17 @@
|
||||
|
||||
use std::{
|
||||
fmt::Display,
|
||||
ops::{AddAssign, Deref}
|
||||
ops::{AddAssign, Deref},
|
||||
};
|
||||
|
||||
|
||||
trait UncheckedCopy: Sized {
|
||||
// This Output is said to be Copy. Yet we default to Self
|
||||
// and it's accepted, not knowing if Self ineed is Copy
|
||||
type Output: Copy
|
||||
type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
|
||||
//~^ ERROR the trait bound `Self: Copy` is not satisfied
|
||||
+ Deref<Target = str>
|
||||
//~^ ERROR the trait bound `Self: Deref` is not satisfied
|
||||
+ AddAssign<&'static str>
|
||||
//~^ ERROR cannot add-assign `&'static str` to `Self`
|
||||
+ From<Self>
|
||||
+ Display = Self;
|
||||
//~^ ERROR `Self` doesn't implement `std::fmt::Display`
|
||||
//~| ERROR the trait bound `Self: Deref` is not satisfied
|
||||
//~| ERROR cannot add-assign `&'static str` to `Self`
|
||||
//~| ERROR `Self` doesn't implement `std::fmt::Display`
|
||||
|
||||
// We said the Output type was Copy, so we can Copy it freely!
|
||||
fn unchecked_copy(other: &Self::Output) -> Self::Output {
|
||||
@ -39,10 +34,6 @@ trait UncheckedCopy: Sized {
|
||||
}
|
||||
|
||||
impl<T> UncheckedCopy for T {}
|
||||
//~^ ERROR `T` doesn't implement `std::fmt::Display`
|
||||
//~| ERROR the trait bound `T: Deref` is not satisfied
|
||||
//~| ERROR cannot add-assign `&'static str` to `T`
|
||||
//~| ERROR the trait bound `T: Copy` is not satisfied
|
||||
|
||||
fn bug<T: UncheckedCopy>(origin: T) {
|
||||
let origin = T::make_origin(origin);
|
||||
|
@ -1,53 +1,11 @@
|
||||
error[E0277]: the trait bound `Self: Copy` is not satisfied
|
||||
--> $DIR/defaults-unsound-62211-1.rs:21:18
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized {
|
||||
| -------------------------- required by `UncheckedCopy`
|
||||
...
|
||||
LL | type Output: Copy
|
||||
| ^^^^ the trait `Copy` is not implemented for `Self`
|
||||
|
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized + Copy {
|
||||
| ^^^^^^
|
||||
|
||||
error[E0277]: cannot add-assign `&'static str` to `Self`
|
||||
--> $DIR/defaults-unsound-62211-1.rs:25:7
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized {
|
||||
| -------------------------- required by `UncheckedCopy`
|
||||
...
|
||||
LL | + AddAssign<&'static str>
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
|
||||
|
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized + AddAssign<&'static str> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `Self: Deref` is not satisfied
|
||||
--> $DIR/defaults-unsound-62211-1.rs:23:7
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized {
|
||||
| -------------------------- required by `UncheckedCopy`
|
||||
...
|
||||
LL | + Deref<Target = str>
|
||||
| ^^^^^^^^^^^^^^^^^^^ the trait `Deref` is not implemented for `Self`
|
||||
|
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized + Deref {
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0277]: `Self` doesn't implement `std::fmt::Display`
|
||||
--> $DIR/defaults-unsound-62211-1.rs:28:7
|
||||
--> $DIR/defaults-unsound-62211-1.rs:20:5
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized {
|
||||
| -------------------------- required by `UncheckedCopy`
|
||||
...
|
||||
LL | + Display = Self;
|
||||
| ^^^^^^^ `Self` cannot be formatted with the default formatter
|
||||
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^^^^^^^
|
||||
| | |
|
||||
| | required by this bound in `UncheckedCopy::Output`
|
||||
| `Self` cannot be formatted with the default formatter
|
||||
|
|
||||
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||
help: consider further restricting `Self`
|
||||
@ -55,75 +13,48 @@ help: consider further restricting `Self`
|
||||
LL | trait UncheckedCopy: Sized + std::fmt::Display {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: `T` doesn't implement `std::fmt::Display`
|
||||
--> $DIR/defaults-unsound-62211-1.rs:41:9
|
||||
error[E0277]: the trait bound `Self: Deref` is not satisfied
|
||||
--> $DIR/defaults-unsound-62211-1.rs:20:5
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized {
|
||||
| ------------- required by a bound in this
|
||||
...
|
||||
LL | + Display = Self;
|
||||
| ------- required by this bound in `UncheckedCopy`
|
||||
...
|
||||
LL | impl<T> UncheckedCopy for T {}
|
||||
| ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter
|
||||
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
|
||||
| ^^^^^^^^^^^^^^^^^^^^-------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| | |
|
||||
| | required by this bound in `UncheckedCopy::Output`
|
||||
| the trait `Deref` is not implemented for `Self`
|
||||
|
|
||||
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||
help: consider restricting type parameter `T`
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
LL | impl<T: std::fmt::Display> UncheckedCopy for T {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
LL | trait UncheckedCopy: Sized + Deref {
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `T: Deref` is not satisfied
|
||||
--> $DIR/defaults-unsound-62211-1.rs:41:9
|
||||
error[E0277]: cannot add-assign `&'static str` to `Self`
|
||||
--> $DIR/defaults-unsound-62211-1.rs:20:5
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized {
|
||||
| ------------- required by a bound in this
|
||||
...
|
||||
LL | + Deref<Target = str>
|
||||
| ------------------- required by this bound in `UncheckedCopy`
|
||||
...
|
||||
LL | impl<T> UncheckedCopy for T {}
|
||||
| ^^^^^^^^^^^^^ the trait `Deref` is not implemented for `T`
|
||||
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| | |
|
||||
| | required by this bound in `UncheckedCopy::Output`
|
||||
| no implementation for `Self += &'static str`
|
||||
|
|
||||
help: consider restricting type parameter `T`
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
LL | impl<T: Deref> UncheckedCopy for T {}
|
||||
| ^^^^^^^
|
||||
LL | trait UncheckedCopy: Sized + AddAssign<&'static str> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: cannot add-assign `&'static str` to `T`
|
||||
--> $DIR/defaults-unsound-62211-1.rs:41:9
|
||||
error[E0277]: the trait bound `Self: Copy` is not satisfied
|
||||
--> $DIR/defaults-unsound-62211-1.rs:20:5
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized {
|
||||
| ------------- required by a bound in this
|
||||
...
|
||||
LL | + AddAssign<&'static str>
|
||||
| ----------------------- required by this bound in `UncheckedCopy`
|
||||
...
|
||||
LL | impl<T> UncheckedCopy for T {}
|
||||
| ^^^^^^^^^^^^^ no implementation for `T += &'static str`
|
||||
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
|
||||
| ^^^^^^^^^^^^^----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| | |
|
||||
| | required by this bound in `UncheckedCopy::Output`
|
||||
| the trait `Copy` is not implemented for `Self`
|
||||
|
|
||||
help: consider restricting type parameter `T`
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
LL | impl<T: AddAssign<&'static str>> UncheckedCopy for T {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | trait UncheckedCopy: Sized + Copy {
|
||||
| ^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `T: Copy` is not satisfied
|
||||
--> $DIR/defaults-unsound-62211-1.rs:41:9
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized {
|
||||
| ------------- required by a bound in this
|
||||
...
|
||||
LL | type Output: Copy
|
||||
| ---- required by this bound in `UncheckedCopy`
|
||||
...
|
||||
LL | impl<T> UncheckedCopy for T {}
|
||||
| ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
|
||||
|
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | impl<T: Copy> UncheckedCopy for T {}
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
@ -11,22 +11,17 @@
|
||||
|
||||
use std::{
|
||||
fmt::Display,
|
||||
ops::{AddAssign, Deref}
|
||||
ops::{AddAssign, Deref},
|
||||
};
|
||||
|
||||
|
||||
trait UncheckedCopy: Sized {
|
||||
// This Output is said to be Copy. Yet we default to Self
|
||||
// and it's accepted, not knowing if Self ineed is Copy
|
||||
type Output: Copy
|
||||
type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
|
||||
//~^ ERROR the trait bound `Self: Copy` is not satisfied
|
||||
+ Deref<Target = str>
|
||||
//~^ ERROR the trait bound `Self: Deref` is not satisfied
|
||||
+ AddAssign<&'static str>
|
||||
//~^ ERROR cannot add-assign `&'static str` to `Self`
|
||||
+ From<Self>
|
||||
+ Display = Self;
|
||||
//~^ ERROR `Self` doesn't implement `std::fmt::Display`
|
||||
//~| ERROR the trait bound `Self: Deref` is not satisfied
|
||||
//~| ERROR cannot add-assign `&'static str` to `Self`
|
||||
//~| ERROR `Self` doesn't implement `std::fmt::Display`
|
||||
|
||||
// We said the Output type was Copy, so we can Copy it freely!
|
||||
fn unchecked_copy(other: &Self::Output) -> Self::Output {
|
||||
@ -39,10 +34,6 @@ trait UncheckedCopy: Sized {
|
||||
}
|
||||
|
||||
impl<T> UncheckedCopy for T {}
|
||||
//~^ ERROR `T` doesn't implement `std::fmt::Display`
|
||||
//~| ERROR the trait bound `T: Deref` is not satisfied
|
||||
//~| ERROR cannot add-assign `&'static str` to `T`
|
||||
//~| ERROR the trait bound `T: Copy` is not satisfied
|
||||
|
||||
fn bug<T: UncheckedCopy>(origin: T) {
|
||||
let origin = T::make_origin(origin);
|
||||
|
@ -1,53 +1,11 @@
|
||||
error[E0277]: the trait bound `Self: Copy` is not satisfied
|
||||
--> $DIR/defaults-unsound-62211-2.rs:21:18
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized {
|
||||
| -------------------------- required by `UncheckedCopy`
|
||||
...
|
||||
LL | type Output: Copy
|
||||
| ^^^^ the trait `Copy` is not implemented for `Self`
|
||||
|
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized + Copy {
|
||||
| ^^^^^^
|
||||
|
||||
error[E0277]: cannot add-assign `&'static str` to `Self`
|
||||
--> $DIR/defaults-unsound-62211-2.rs:25:7
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized {
|
||||
| -------------------------- required by `UncheckedCopy`
|
||||
...
|
||||
LL | + AddAssign<&'static str>
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
|
||||
|
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized + AddAssign<&'static str> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `Self: Deref` is not satisfied
|
||||
--> $DIR/defaults-unsound-62211-2.rs:23:7
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized {
|
||||
| -------------------------- required by `UncheckedCopy`
|
||||
...
|
||||
LL | + Deref<Target = str>
|
||||
| ^^^^^^^^^^^^^^^^^^^ the trait `Deref` is not implemented for `Self`
|
||||
|
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized + Deref {
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0277]: `Self` doesn't implement `std::fmt::Display`
|
||||
--> $DIR/defaults-unsound-62211-2.rs:28:7
|
||||
--> $DIR/defaults-unsound-62211-2.rs:20:5
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized {
|
||||
| -------------------------- required by `UncheckedCopy`
|
||||
...
|
||||
LL | + Display = Self;
|
||||
| ^^^^^^^ `Self` cannot be formatted with the default formatter
|
||||
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^^^^^^^
|
||||
| | |
|
||||
| | required by this bound in `UncheckedCopy::Output`
|
||||
| `Self` cannot be formatted with the default formatter
|
||||
|
|
||||
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||
help: consider further restricting `Self`
|
||||
@ -55,75 +13,48 @@ help: consider further restricting `Self`
|
||||
LL | trait UncheckedCopy: Sized + std::fmt::Display {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: `T` doesn't implement `std::fmt::Display`
|
||||
--> $DIR/defaults-unsound-62211-2.rs:41:9
|
||||
error[E0277]: the trait bound `Self: Deref` is not satisfied
|
||||
--> $DIR/defaults-unsound-62211-2.rs:20:5
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized {
|
||||
| ------------- required by a bound in this
|
||||
...
|
||||
LL | + Display = Self;
|
||||
| ------- required by this bound in `UncheckedCopy`
|
||||
...
|
||||
LL | impl<T> UncheckedCopy for T {}
|
||||
| ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter
|
||||
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
|
||||
| ^^^^^^^^^^^^^^^^^^^^-------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| | |
|
||||
| | required by this bound in `UncheckedCopy::Output`
|
||||
| the trait `Deref` is not implemented for `Self`
|
||||
|
|
||||
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||
help: consider restricting type parameter `T`
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
LL | impl<T: std::fmt::Display> UncheckedCopy for T {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
LL | trait UncheckedCopy: Sized + Deref {
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `T: Deref` is not satisfied
|
||||
--> $DIR/defaults-unsound-62211-2.rs:41:9
|
||||
error[E0277]: cannot add-assign `&'static str` to `Self`
|
||||
--> $DIR/defaults-unsound-62211-2.rs:20:5
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized {
|
||||
| ------------- required by a bound in this
|
||||
...
|
||||
LL | + Deref<Target = str>
|
||||
| ------------------- required by this bound in `UncheckedCopy`
|
||||
...
|
||||
LL | impl<T> UncheckedCopy for T {}
|
||||
| ^^^^^^^^^^^^^ the trait `Deref` is not implemented for `T`
|
||||
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| | |
|
||||
| | required by this bound in `UncheckedCopy::Output`
|
||||
| no implementation for `Self += &'static str`
|
||||
|
|
||||
help: consider restricting type parameter `T`
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
LL | impl<T: Deref> UncheckedCopy for T {}
|
||||
| ^^^^^^^
|
||||
LL | trait UncheckedCopy: Sized + AddAssign<&'static str> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: cannot add-assign `&'static str` to `T`
|
||||
--> $DIR/defaults-unsound-62211-2.rs:41:9
|
||||
error[E0277]: the trait bound `Self: Copy` is not satisfied
|
||||
--> $DIR/defaults-unsound-62211-2.rs:20:5
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized {
|
||||
| ------------- required by a bound in this
|
||||
...
|
||||
LL | + AddAssign<&'static str>
|
||||
| ----------------------- required by this bound in `UncheckedCopy`
|
||||
...
|
||||
LL | impl<T> UncheckedCopy for T {}
|
||||
| ^^^^^^^^^^^^^ no implementation for `T += &'static str`
|
||||
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
|
||||
| ^^^^^^^^^^^^^----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| | |
|
||||
| | required by this bound in `UncheckedCopy::Output`
|
||||
| the trait `Copy` is not implemented for `Self`
|
||||
|
|
||||
help: consider restricting type parameter `T`
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
LL | impl<T: AddAssign<&'static str>> UncheckedCopy for T {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | trait UncheckedCopy: Sized + Copy {
|
||||
| ^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `T: Copy` is not satisfied
|
||||
--> $DIR/defaults-unsound-62211-2.rs:41:9
|
||||
|
|
||||
LL | trait UncheckedCopy: Sized {
|
||||
| ------------- required by a bound in this
|
||||
...
|
||||
LL | type Output: Copy
|
||||
| ---- required by this bound in `UncheckedCopy`
|
||||
...
|
||||
LL | impl<T> UncheckedCopy for T {}
|
||||
| ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
|
||||
|
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | impl<T: Copy> UncheckedCopy for T {}
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
11
src/test/ui/associated-types/defaults-wf.rs
Normal file
11
src/test/ui/associated-types/defaults-wf.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// Check that associated type defaults are wf checked.
|
||||
|
||||
#![feature(associated_type_defaults)]
|
||||
|
||||
// Default types must always be wf
|
||||
trait Tr3 {
|
||||
type Ty = Vec<[u8]>;
|
||||
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
|
||||
}
|
||||
|
||||
fn main() {}
|
16
src/test/ui/associated-types/defaults-wf.stderr
Normal file
16
src/test/ui/associated-types/defaults-wf.stderr
Normal file
@ -0,0 +1,16 @@
|
||||
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||
--> $DIR/defaults-wf.rs:7:5
|
||||
|
|
||||
LL | type Ty = Vec<[u8]>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
::: $SRC_DIR/alloc/src/vec.rs:LL:COL
|
||||
|
|
||||
LL | pub struct Vec<T> {
|
||||
| - required by this bound in `Vec`
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `[u8]`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -9,7 +9,6 @@ LL | fn baz() -> impl Bar<Item = i32> {
|
||||
|
|
||||
= note: expected associated type `<impl Bar as Foo>::Item`
|
||||
found type `i32`
|
||||
= note: the return type of a function must have a statically known size
|
||||
help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32`
|
||||
|
|
||||
LL | fn bar() -> impl Bar<Item = i32> {
|
||||
|
@ -4,12 +4,13 @@
|
||||
// type-checked.
|
||||
|
||||
trait Foo<T: Default + ToString> {
|
||||
type Out: Default + ToString + ?Sized = dyn ToString; //~ error: not satisfied
|
||||
type Out: Default + ToString + ?Sized = dyn ToString; //~ ERROR not satisfied
|
||||
}
|
||||
|
||||
impl Foo<u32> for () {} //~ error: not satisfied
|
||||
impl Foo<u64> for () {} //~ error: not satisfied
|
||||
impl Foo<u32> for () {}
|
||||
impl Foo<u64> for () {}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(<() as Foo<u32>>::Out::default().to_string(), "false");
|
||||
//~^ ERROR no function or associated item named `default` found for trait object
|
||||
}
|
||||
|
@ -1,33 +1,19 @@
|
||||
error[E0277]: the trait bound `(dyn ToString + 'static): Default` is not satisfied
|
||||
--> $DIR/issue-43924.rs:7:15
|
||||
--> $DIR/issue-43924.rs:7:5
|
||||
|
|
||||
LL | trait Foo<T: Default + ToString> {
|
||||
| -------------------------------- required by `Foo`
|
||||
LL | type Out: Default + ToString + ?Sized = dyn ToString;
|
||||
| ^^^^^^^ the trait `Default` is not implemented for `(dyn ToString + 'static)`
|
||||
| ^^^^^^^^^^-------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| | |
|
||||
| | required by this bound in `Foo::Out`
|
||||
| the trait `Default` is not implemented for `(dyn ToString + 'static)`
|
||||
|
||||
error[E0277]: the trait bound `(dyn ToString + 'static): Default` is not satisfied
|
||||
--> $DIR/issue-43924.rs:10:6
|
||||
error[E0599]: no function or associated item named `default` found for trait object `(dyn ToString + 'static)` in the current scope
|
||||
--> $DIR/issue-43924.rs:14:39
|
||||
|
|
||||
LL | trait Foo<T: Default + ToString> {
|
||||
| --- required by a bound in this
|
||||
LL | type Out: Default + ToString + ?Sized = dyn ToString;
|
||||
| ------- required by this bound in `Foo`
|
||||
...
|
||||
LL | impl Foo<u32> for () {}
|
||||
| ^^^^^^^^ the trait `Default` is not implemented for `(dyn ToString + 'static)`
|
||||
LL | assert_eq!(<() as Foo<u32>>::Out::default().to_string(), "false");
|
||||
| ^^^^^^^ function or associated item not found in `(dyn ToString + 'static)`
|
||||
|
||||
error[E0277]: the trait bound `(dyn ToString + 'static): Default` is not satisfied
|
||||
--> $DIR/issue-43924.rs:11:6
|
||||
|
|
||||
LL | trait Foo<T: Default + ToString> {
|
||||
| --- required by a bound in this
|
||||
LL | type Out: Default + ToString + ?Sized = dyn ToString;
|
||||
| ------- required by this bound in `Foo`
|
||||
...
|
||||
LL | impl Foo<u64> for () {}
|
||||
| ^^^^^^^^ the trait `Default` is not implemented for `(dyn ToString + 'static)`
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
Some errors have detailed explanations: E0277, E0599.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
@ -1,10 +1,11 @@
|
||||
error[E0277]: the size for values of type `Self` cannot be known at compilation time
|
||||
--> $DIR/issue-63593.rs:9:5
|
||||
|
|
||||
LL | trait MyTrait {
|
||||
| ------------- required by `MyTrait`
|
||||
LL | type This = Self;
|
||||
| ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| doesn't have a size known at compile-time
|
||||
| required by this bound in `MyTrait::This`
|
||||
|
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
|
@ -14,7 +14,6 @@ trait MPU {
|
||||
struct S;
|
||||
|
||||
impl MPU for S { }
|
||||
//~^ ERROR the trait bound `T: MyDisplay` is not satisfied
|
||||
|
||||
trait MyWrite {
|
||||
fn my_write(&self, _: &dyn MyDisplay) { }
|
||||
@ -43,6 +42,7 @@ impl ProcessType for Process {
|
||||
// FulfillmentError(Obligation(predicate=Binder(TraitPredicate(<T as MyDisplay>)),
|
||||
// depth=1),Unimplemented)
|
||||
let closure = |config: &mut <S as MPU>::MpuConfig| writer.my_write(&config);
|
||||
//~^ ERROR the trait bound `T: MyDisplay` is not satisfied
|
||||
closure(valref);
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,20 @@
|
||||
error[E0277]: the trait bound `T: MyDisplay` is not satisfied
|
||||
--> $DIR/issue-65774-1.rs:10:21
|
||||
--> $DIR/issue-65774-1.rs:10:5
|
||||
|
|
||||
LL | trait MPU {
|
||||
| --------- required by `MPU`
|
||||
LL | type MpuConfig: MyDisplay = T;
|
||||
| ^^^^^^^^^ the trait `MyDisplay` is not implemented for `T`
|
||||
| ^^^^^^^^^^^^^^^^---------^^^^^
|
||||
| | |
|
||||
| | required by this bound in `MPU::MpuConfig`
|
||||
| the trait `MyDisplay` is not implemented for `T`
|
||||
|
||||
error[E0277]: the trait bound `T: MyDisplay` is not satisfied
|
||||
--> $DIR/issue-65774-1.rs:16:6
|
||||
--> $DIR/issue-65774-1.rs:44:76
|
||||
|
|
||||
LL | trait MPU {
|
||||
| --- required by a bound in this
|
||||
LL | type MpuConfig: MyDisplay = T;
|
||||
| --------- required by this bound in `MPU`
|
||||
...
|
||||
LL | impl MPU for S { }
|
||||
| ^^^ the trait `MyDisplay` is not implemented for `T`
|
||||
LL | let closure = |config: &mut <S as MPU>::MpuConfig| writer.my_write(&config);
|
||||
| ^^^^^^^ the trait `MyDisplay` is not implemented for `T`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `MyDisplay` for `&mut T`
|
||||
= note: required for the cast to the object type `dyn MyDisplay`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -14,7 +14,6 @@ trait MPU {
|
||||
struct S;
|
||||
|
||||
impl MPU for S { }
|
||||
//~^ ERROR the trait bound `T: MyDisplay` is not satisfied
|
||||
|
||||
trait MyWrite {
|
||||
fn my_write(&self, _: &dyn MyDisplay) { }
|
||||
@ -38,6 +37,7 @@ impl ProcessType for Process {
|
||||
// // `Unimplemented` selecting `Binder(<T as MyDisplay>)` during codegen
|
||||
//
|
||||
writer.my_write(valref)
|
||||
//~^ ERROR the trait bound `T: MyDisplay` is not satisfied
|
||||
|
||||
// This one causes the ICE:
|
||||
// FulfillmentError(Obligation(predicate=Binder(TraitPredicate(<T as MyDisplay>)),
|
||||
|
@ -1,21 +1,19 @@
|
||||
error[E0277]: the trait bound `T: MyDisplay` is not satisfied
|
||||
--> $DIR/issue-65774-2.rs:10:21
|
||||
--> $DIR/issue-65774-2.rs:10:5
|
||||
|
|
||||
LL | trait MPU {
|
||||
| --------- required by `MPU`
|
||||
LL | type MpuConfig: MyDisplay = T;
|
||||
| ^^^^^^^^^ the trait `MyDisplay` is not implemented for `T`
|
||||
| ^^^^^^^^^^^^^^^^---------^^^^^
|
||||
| | |
|
||||
| | required by this bound in `MPU::MpuConfig`
|
||||
| the trait `MyDisplay` is not implemented for `T`
|
||||
|
||||
error[E0277]: the trait bound `T: MyDisplay` is not satisfied
|
||||
--> $DIR/issue-65774-2.rs:16:6
|
||||
--> $DIR/issue-65774-2.rs:39:25
|
||||
|
|
||||
LL | trait MPU {
|
||||
| --- required by a bound in this
|
||||
LL | type MpuConfig: MyDisplay = T;
|
||||
| --------- required by this bound in `MPU`
|
||||
...
|
||||
LL | impl MPU for S { }
|
||||
| ^^^ the trait `MyDisplay` is not implemented for `T`
|
||||
LL | writer.my_write(valref)
|
||||
| ^^^^^^ the trait `MyDisplay` is not implemented for `T`
|
||||
|
|
||||
= note: required for the cast to the object type `dyn MyDisplay`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -9,9 +9,10 @@ trait Bar2 {
|
||||
struct Foo;
|
||||
struct Foo2;
|
||||
|
||||
impl Bar for Foo { //~ ERROR type mismatch resolving `<Foo2 as Bar2>::Ok == char`
|
||||
impl Bar for Foo {
|
||||
type Ok = ();
|
||||
type Sibling = Foo2;
|
||||
//~^ ERROR type mismatch resolving `<Foo2 as Bar2>::Ok == char`
|
||||
}
|
||||
impl Bar2 for Foo2 {
|
||||
type Ok = u32;
|
||||
|
@ -1,8 +1,11 @@
|
||||
error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == char`
|
||||
--> $DIR/issue-72806.rs:12:6
|
||||
--> $DIR/issue-72806.rs:14:5
|
||||
|
|
||||
LL | impl Bar for Foo {
|
||||
| ^^^ expected `u32`, found `char`
|
||||
LL | type Sibling: Bar2<Ok=char>;
|
||||
| ------- required by this bound in `Bar::Sibling`
|
||||
...
|
||||
LL | type Sibling = Foo2;
|
||||
| ^^^^^^^^^^^^^^^^^^^^ expected `char`, found `u32`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
26
src/test/ui/associated-types/object-normalization.rs
Normal file
26
src/test/ui/associated-types/object-normalization.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// ignore-tidy-linelength
|
||||
|
||||
// Check that we normalize super predicates for object candidates.
|
||||
|
||||
// check-pass
|
||||
|
||||
use std::ops::Index;
|
||||
|
||||
fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
|
||||
// To prove
|
||||
// `dyn SVec<Item = T, Output = T>: SVec`
|
||||
// we need to show
|
||||
// `dyn SVec<Item = T, Output = T> as Index>::Output == <dyn SVec<Item = T, Output = T> as SVec>::Item`
|
||||
// which, with the current normalization strategy, has to be eagerly
|
||||
// normalized to:
|
||||
// `dyn SVec<Item = T, Output = T> as Index>::Output == T`.
|
||||
let _ = s.len();
|
||||
}
|
||||
|
||||
trait SVec: Index<usize, Output = <Self as SVec>::Item> {
|
||||
type Item;
|
||||
|
||||
fn len(&self) -> usize;
|
||||
}
|
||||
|
||||
fn main() {}
|
39
src/test/ui/associated-types/param-env-normalize-cycle.rs
Normal file
39
src/test/ui/associated-types/param-env-normalize-cycle.rs
Normal file
@ -0,0 +1,39 @@
|
||||
// Minimized case from typenum that didn't compile because:
|
||||
// - We tried to normalize the ParamEnv of the second impl
|
||||
// - This requires trying to normalize `GrEq<Self, Square<Square<U>>>`
|
||||
// - This requires proving `Square<Square<U>>: Sized` so that the first impl
|
||||
// applies
|
||||
// - This requires Providing `Square<Square<U>>` is well-formed, so that we
|
||||
// can use the `Sized` bound on `Mul::Output`
|
||||
// - This requires proving `Square<U>: Mul`
|
||||
// - But first we tried normalizing the whole obligation, including the
|
||||
// ParamEnv, which leads to a cycle error.
|
||||
|
||||
// check-pass
|
||||
|
||||
trait PrivateSquareRoot {}
|
||||
|
||||
pub trait Mul<Rhs = Self> {
|
||||
type Output;
|
||||
}
|
||||
|
||||
pub trait IsGreaterOrEqual<Rhs> {
|
||||
type Output;
|
||||
}
|
||||
|
||||
pub type Square<A> = <A as Mul>::Output;
|
||||
pub type GrEq<A, B> = <A as IsGreaterOrEqual<B>>::Output;
|
||||
|
||||
impl<A, B> IsGreaterOrEqual<B> for A {
|
||||
type Output = ();
|
||||
}
|
||||
|
||||
impl<U> PrivateSquareRoot for U
|
||||
where
|
||||
U: Mul,
|
||||
Square<U>: Mul,
|
||||
GrEq<Self, Square<Square<U>>>: Sized,
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -8,7 +8,10 @@ impl Foo for () {
|
||||
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
|
||||
}
|
||||
|
||||
trait Baz where Self::Assoc: Bar {
|
||||
trait Baz
|
||||
where
|
||||
Self::Assoc: Bar,
|
||||
{
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
@ -16,7 +19,10 @@ impl Baz for () {
|
||||
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
|
||||
}
|
||||
|
||||
trait Bat where <Self as Bat>::Assoc: Bar {
|
||||
trait Bat
|
||||
where
|
||||
<Self as Bat>::Assoc: Bar,
|
||||
{
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
|
@ -1,31 +1,35 @@
|
||||
error[E0277]: the trait bound `bool: Bar` is not satisfied
|
||||
--> $DIR/point-at-type-on-obligation-failure-2.rs:8:18
|
||||
--> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
|
||||
|
|
||||
LL | trait Foo {
|
||||
| --- required by a bound in this
|
||||
LL | type Assoc: Bar;
|
||||
| --- required by this bound in `Foo`
|
||||
| --- required by this bound in `Foo::Assoc`
|
||||
...
|
||||
LL | type Assoc = bool;
|
||||
| ^^^^ the trait `Bar` is not implemented for `bool`
|
||||
| ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
|
||||
|
||||
error[E0277]: the trait bound `bool: Bar` is not satisfied
|
||||
--> $DIR/point-at-type-on-obligation-failure-2.rs:16:18
|
||||
--> $DIR/point-at-type-on-obligation-failure-2.rs:19:5
|
||||
|
|
||||
LL | trait Baz where Self::Assoc: Bar {
|
||||
| --- required by this bound in `Baz`
|
||||
LL | Self::Assoc: Bar,
|
||||
| --- required by this bound in `Baz::Assoc`
|
||||
LL | {
|
||||
LL | type Assoc;
|
||||
| ----- required by a bound in this
|
||||
...
|
||||
LL | type Assoc = bool;
|
||||
| ^^^^ the trait `Bar` is not implemented for `bool`
|
||||
| ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
|
||||
|
||||
error[E0277]: the trait bound `bool: Bar` is not satisfied
|
||||
--> $DIR/point-at-type-on-obligation-failure-2.rs:24:18
|
||||
--> $DIR/point-at-type-on-obligation-failure-2.rs:30:5
|
||||
|
|
||||
LL | trait Bat where <Self as Bat>::Assoc: Bar {
|
||||
| --- required by this bound in `Bat`
|
||||
LL | <Self as Bat>::Assoc: Bar,
|
||||
| --- required by this bound in `Bat::Assoc`
|
||||
LL | {
|
||||
LL | type Assoc;
|
||||
| ----- required by a bound in this
|
||||
...
|
||||
LL | type Assoc = bool;
|
||||
| ^^^^ the trait `Bar` is not implemented for `bool`
|
||||
| ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -10,8 +10,9 @@ struct Foo;
|
||||
struct Foo2;
|
||||
|
||||
impl Bar for Foo {
|
||||
type Ok = (); //~ ERROR type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
|
||||
type Ok = ();
|
||||
type Sibling = Foo2;
|
||||
//~^ ERROR type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
|
||||
}
|
||||
impl Bar2 for Foo2 {
|
||||
type Ok = u32;
|
||||
|
@ -1,8 +1,11 @@
|
||||
error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
|
||||
--> $DIR/point-at-type-on-obligation-failure.rs:13:15
|
||||
--> $DIR/point-at-type-on-obligation-failure.rs:14:5
|
||||
|
|
||||
LL | type Ok = ();
|
||||
| ^^ expected `u32`, found `()`
|
||||
LL | type Sibling: Bar2<Ok=Self::Ok>;
|
||||
| ----------- required by this bound in `Bar::Sibling`
|
||||
...
|
||||
LL | type Sibling = Foo2;
|
||||
| ^^^^^^^^^^^^^^^^^^^^ expected `()`, found `u32`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
18
src/test/ui/associated-types/wf-cycle-2.rs
Normal file
18
src/test/ui/associated-types/wf-cycle-2.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// check-pass
|
||||
|
||||
trait IntoIt {
|
||||
type Item;
|
||||
}
|
||||
|
||||
impl<I> IntoIt for I {
|
||||
type Item = ();
|
||||
}
|
||||
|
||||
trait BaseGraph
|
||||
where
|
||||
<Self::VertexIter as IntoIt>::Item: Sized,
|
||||
{
|
||||
type VertexIter: IntoIt;
|
||||
}
|
||||
|
||||
fn main() {}
|
13
src/test/ui/associated-types/wf-cycle.rs
Normal file
13
src/test/ui/associated-types/wf-cycle.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// check-pass
|
||||
|
||||
trait A {
|
||||
type U: Copy;
|
||||
}
|
||||
|
||||
trait B where
|
||||
<Self::V as A>::U: Copy,
|
||||
{
|
||||
type V: A;
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -3,12 +3,8 @@ error[E0277]: `()` is not a future
|
||||
|
|
||||
LL | fn get_future() -> impl Future<Output = ()> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
|
||||
LL |
|
||||
LL | panic!()
|
||||
| -------- this returned value is of type `!`
|
||||
|
|
||||
= help: the trait `Future` is not implemented for `()`
|
||||
= note: the return type of a function must have a statically known size
|
||||
|
||||
error[E0698]: type inside `async fn` body must be known in this context
|
||||
--> $DIR/async-error-span.rs:13:9
|
||||
|
@ -27,33 +27,18 @@ error[E0609]: no field `0` on type `impl Future`
|
||||
|
|
||||
LL | let _: i32 = tuple().0;
|
||||
| ^
|
||||
|
|
||||
help: consider awaiting before field access
|
||||
|
|
||||
LL | let _: i32 = tuple().await.0;
|
||||
| ^^^^^^
|
||||
|
||||
error[E0609]: no field `a` on type `impl Future`
|
||||
--> $DIR/issue-61076.rs:60:28
|
||||
|
|
||||
LL | let _: i32 = struct_().a;
|
||||
| ^
|
||||
|
|
||||
help: consider awaiting before field access
|
||||
|
|
||||
LL | let _: i32 = struct_().await.a;
|
||||
| ^^^^^^
|
||||
|
||||
error[E0599]: no method named `method` found for opaque type `impl Future` in the current scope
|
||||
--> $DIR/issue-61076.rs:62:15
|
||||
|
|
||||
LL | struct_().method();
|
||||
| ^^^^^^ method not found in `impl Future`
|
||||
|
|
||||
help: consider awaiting before this method call
|
||||
|
|
||||
LL | struct_().await.method();
|
||||
| ^^^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-61076.rs:69:9
|
||||
@ -66,10 +51,6 @@ LL | Tuple(_) => {}
|
||||
|
|
||||
= note: expected opaque type `impl Future`
|
||||
found struct `Tuple`
|
||||
help: consider awaiting on the future
|
||||
|
|
||||
LL | match tuple().await {
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
@ -1,17 +1,8 @@
|
||||
error: future cannot be sent between threads safely
|
||||
--> $DIR/issue-64130-4-async-move.rs:15:17
|
||||
|
|
||||
LL | pub fn foo() -> impl Future + Send {
|
||||
| ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
|
||||
...
|
||||
LL | / async move {
|
||||
LL | | match client.status() {
|
||||
LL | | 200 => {
|
||||
LL | | let _x = get().await;
|
||||
... |
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_____- this returned value is of type `impl Future`
|
||||
LL | pub fn foo() -> impl Future + Send {
|
||||
| ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
|
||||
|
|
||||
= help: the trait `Sync` is not implemented for `(dyn Any + Send + 'static)`
|
||||
note: future is not `Send` as this value is used across an await
|
||||
@ -30,7 +21,6 @@ help: consider moving this into a `let` binding to create a shorter lived borrow
|
||||
|
|
||||
LL | match client.status() {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
= note: the return type of a function must have a statically known size
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
error[E0515]: cannot return value referencing local variable `s`
|
||||
--> $DIR/issue-67765-async-diagnostic.rs:13:11
|
||||
--> $DIR/issue-67765-async-diagnostic.rs:13:5
|
||||
|
|
||||
LL | let b = &s[..];
|
||||
| - `s` is borrowed here
|
||||
LL |
|
||||
LL | Err(b)?;
|
||||
| ^ returns a value referencing data owned by the current function
|
||||
| ^^^^^^^ returns a value referencing data owned by the current function
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -3,16 +3,12 @@ error: future cannot be sent between threads safely
|
||||
|
|
||||
LL | fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
|
||||
LL |
|
||||
LL | async { (ty, ty1) }
|
||||
| ------------------- this returned value is of type `impl Future`
|
||||
|
|
||||
note: captured value is not `Send`
|
||||
--> $DIR/issue-70818.rs:6:18
|
||||
|
|
||||
LL | async { (ty, ty1) }
|
||||
| ^^^ has type `U` which is not `Send`
|
||||
= note: the return type of a function must have a statically known size
|
||||
help: consider restricting type parameter `U`
|
||||
|
|
||||
LL | fn foo<T: Send, U: Send>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
|
||||
|
@ -15,19 +15,6 @@ impl Foo for str { }
|
||||
// Implicit `T: Sized` bound.
|
||||
impl<T> Foo for Option<T> { }
|
||||
|
||||
impl Bar for () {
|
||||
type Item = i32;
|
||||
}
|
||||
|
||||
impl<T> Bar for Option<T> {
|
||||
type Item = Option<T>;
|
||||
}
|
||||
|
||||
impl Bar for f32 {
|
||||
type Item = f32;
|
||||
//~^ ERROR the trait bound `f32: Foo` is not satisfied
|
||||
}
|
||||
|
||||
trait Baz<U: ?Sized> where U: Foo { }
|
||||
|
||||
impl Baz<i32> for i32 { }
|
||||
|
@ -10,18 +10,7 @@ LL | impl Foo for str { }
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
|
||||
error[E0277]: the trait bound `f32: Foo` is not satisfied
|
||||
--> $DIR/impl_wf.rs:27:17
|
||||
|
|
||||
LL | trait Bar {
|
||||
| --- required by a bound in this
|
||||
LL | type Item: Foo;
|
||||
| --- required by this bound in `Bar`
|
||||
...
|
||||
LL | type Item = f32;
|
||||
| ^^^ the trait `Foo` is not implemented for `f32`
|
||||
|
||||
error[E0277]: the trait bound `f32: Foo` is not satisfied
|
||||
--> $DIR/impl_wf.rs:35:6
|
||||
--> $DIR/impl_wf.rs:22:6
|
||||
|
|
||||
LL | trait Baz<U: ?Sized> where U: Foo { }
|
||||
| --- required by this bound in `Baz`
|
||||
@ -29,6 +18,6 @@ LL | trait Baz<U: ?Sized> where U: Foo { }
|
||||
LL | impl Baz<f32> for f32 { }
|
||||
| ^^^^^^^^ the trait `Foo` is not implemented for `f32`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
33
src/test/ui/chalkify/impl_wf_2.rs
Normal file
33
src/test/ui/chalkify/impl_wf_2.rs
Normal file
@ -0,0 +1,33 @@
|
||||
// Split out of impl_wf.rs to work around rust aborting compilation early
|
||||
|
||||
// compile-flags: -Z chalk
|
||||
|
||||
trait Foo: Sized { }
|
||||
|
||||
trait Bar {
|
||||
type Item: Foo;
|
||||
}
|
||||
|
||||
impl Foo for i32 { }
|
||||
|
||||
// Implicit `T: Sized` bound.
|
||||
impl<T> Foo for Option<T> { }
|
||||
|
||||
impl Bar for () {
|
||||
type Item = i32;
|
||||
}
|
||||
|
||||
impl<T> Bar for Option<T> {
|
||||
type Item = Option<T>;
|
||||
}
|
||||
|
||||
impl Bar for f32 {
|
||||
type Item = f32;
|
||||
//~^ ERROR the trait bound `f32: Foo` is not satisfied
|
||||
}
|
||||
|
||||
trait Baz<U: ?Sized> where U: Foo { }
|
||||
|
||||
impl Baz<i32> for i32 { }
|
||||
|
||||
fn main() {}
|
12
src/test/ui/chalkify/impl_wf_2.stderr
Normal file
12
src/test/ui/chalkify/impl_wf_2.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0277]: the trait bound `f32: Foo` is not satisfied
|
||||
--> $DIR/impl_wf_2.rs:25:5
|
||||
|
|
||||
LL | type Item: Foo;
|
||||
| --- required by this bound in `Bar::Item`
|
||||
...
|
||||
LL | type Item = f32;
|
||||
| ^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `f32`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -9,4 +9,5 @@ impl<'g> T<'g> for u32 {
|
||||
fn main() {
|
||||
(&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
|
||||
//~^ ERROR: type mismatch in closure arguments
|
||||
//~| ERROR: size for values of type `<u32 as T<'_>>::V` cannot be known at compilation time
|
||||
}
|
||||
|
@ -9,6 +9,24 @@ LL | (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
|
||||
|
|
||||
= note: required for the cast to the object type `dyn for<'x> Fn(<u32 as T<'x>>::V)`
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0277]: the size for values of type `<u32 as T<'_>>::V` cannot be known at compilation time
|
||||
--> $DIR/issue-41366.rs:10:8
|
||||
|
|
||||
LL | (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
|
||||
| ^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `<u32 as T<'_>>::V`
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | fn main() where <u32 as T<'_>>::V: Sized {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||
|
|
||||
LL | (&|&_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
|
||||
| ^
|
||||
|
||||
For more information about this error, try `rustc --explain E0631`.
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0631.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
@ -5,7 +5,6 @@ LL | fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `()`
|
||||
= note: the return type of a function must have a statically known size
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user