Initial support for auto traits with default bounds
This commit is contained in:
parent
79de6c0bbe
commit
581c5fbc40
24 changed files with 830 additions and 86 deletions
|
@ -433,6 +433,12 @@ language_item_table! {
|
||||||
// Experimental lang items for implementing contract pre- and post-condition checking.
|
// Experimental lang items for implementing contract pre- and post-condition checking.
|
||||||
ContractBuildCheckEnsures, sym::contract_build_check_ensures, contract_build_check_ensures_fn, Target::Fn, GenericRequirement::None;
|
ContractBuildCheckEnsures, sym::contract_build_check_ensures, contract_build_check_ensures_fn, Target::Fn, GenericRequirement::None;
|
||||||
ContractCheckRequires, sym::contract_check_requires, contract_check_requires_fn, Target::Fn, GenericRequirement::None;
|
ContractCheckRequires, sym::contract_check_requires, contract_check_requires_fn, Target::Fn, GenericRequirement::None;
|
||||||
|
|
||||||
|
// Experimental lang items for `MCP: Low level components for async drop`(https://github.com/rust-lang/compiler-team/issues/727)
|
||||||
|
DefaultTrait4, sym::default_trait4, default_trait4_trait, Target::Trait, GenericRequirement::None;
|
||||||
|
DefaultTrait3, sym::default_trait3, default_trait3_trait, Target::Trait, GenericRequirement::None;
|
||||||
|
DefaultTrait2, sym::default_trait2, default_trait2_trait, Target::Trait, GenericRequirement::None;
|
||||||
|
DefaultTrait1, sym::default_trait1, default_trait1_trait, Target::Trait, GenericRequirement::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The requirement imposed on the generics of a lang item
|
/// The requirement imposed on the generics of a lang item
|
||||||
|
|
|
@ -341,9 +341,8 @@ fn bounds_from_generic_predicates<'tcx>(
|
||||||
ty::ClauseKind::Trait(trait_predicate) => {
|
ty::ClauseKind::Trait(trait_predicate) => {
|
||||||
let entry = types.entry(trait_predicate.self_ty()).or_default();
|
let entry = types.entry(trait_predicate.self_ty()).or_default();
|
||||||
let def_id = trait_predicate.def_id();
|
let def_id = trait_predicate.def_id();
|
||||||
if Some(def_id) != tcx.lang_items().sized_trait() {
|
if !tcx.is_default_trait(def_id) {
|
||||||
// Type params are `Sized` by default, do not add that restriction to the list
|
// Do not add that restriction to the list if it is a positive requirement.
|
||||||
// if it is a positive requirement.
|
|
||||||
entry.push(trait_predicate.def_id());
|
entry.push(trait_predicate.def_id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,13 +38,13 @@ fn associated_type_bounds<'tcx>(
|
||||||
let icx = ItemCtxt::new(tcx, assoc_item_def_id);
|
let icx = ItemCtxt::new(tcx, assoc_item_def_id);
|
||||||
let mut bounds = Vec::new();
|
let mut bounds = Vec::new();
|
||||||
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
|
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
|
||||||
// Associated types are implicitly sized unless a `?Sized` bound is found
|
// Implicit bounds are added to associated types unless a `?Trait` bound is found
|
||||||
match filter {
|
match filter {
|
||||||
PredicateFilter::All
|
PredicateFilter::All
|
||||||
| PredicateFilter::SelfOnly
|
| PredicateFilter::SelfOnly
|
||||||
| PredicateFilter::SelfTraitThatDefines(_)
|
| PredicateFilter::SelfTraitThatDefines(_)
|
||||||
| PredicateFilter::SelfAndAssociatedTypeBounds => {
|
| PredicateFilter::SelfAndAssociatedTypeBounds => {
|
||||||
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
|
icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span);
|
||||||
}
|
}
|
||||||
// `ConstIfConst` is only interested in `~const` bounds.
|
// `ConstIfConst` is only interested in `~const` bounds.
|
||||||
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
|
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
|
||||||
|
@ -327,14 +327,13 @@ fn opaque_type_bounds<'tcx>(
|
||||||
let icx = ItemCtxt::new(tcx, opaque_def_id);
|
let icx = ItemCtxt::new(tcx, opaque_def_id);
|
||||||
let mut bounds = Vec::new();
|
let mut bounds = Vec::new();
|
||||||
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
|
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
|
||||||
// Opaque types are implicitly sized unless a `?Sized` bound is found
|
// Implicit bounds are added to opaque types unless a `?Trait` bound is found
|
||||||
match filter {
|
match filter {
|
||||||
PredicateFilter::All
|
PredicateFilter::All
|
||||||
| PredicateFilter::SelfOnly
|
| PredicateFilter::SelfOnly
|
||||||
| PredicateFilter::SelfTraitThatDefines(_)
|
| PredicateFilter::SelfTraitThatDefines(_)
|
||||||
| PredicateFilter::SelfAndAssociatedTypeBounds => {
|
| PredicateFilter::SelfAndAssociatedTypeBounds => {
|
||||||
// Associated types are implicitly sized unless a `?Sized` bound is found
|
icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span);
|
||||||
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
|
|
||||||
}
|
}
|
||||||
//`ConstIfConst` is only interested in `~const` bounds.
|
//`ConstIfConst` is only interested in `~const` bounds.
|
||||||
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
|
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
|
||||||
|
|
|
@ -165,12 +165,42 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||||
|
|
||||||
ItemKind::Trait(_, _, _, _, self_bounds, ..)
|
ItemKind::Trait(_, _, _, _, self_bounds, ..)
|
||||||
| ItemKind::TraitAlias(_, _, self_bounds) => {
|
| ItemKind::TraitAlias(_, _, self_bounds) => {
|
||||||
is_trait = Some(self_bounds);
|
is_trait = Some((self_bounds, item.span));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Node::TraitItem(item) = node {
|
||||||
|
let parent = tcx.local_parent(item.hir_id().owner.def_id);
|
||||||
|
let Node::Item(parent_trait) = tcx.hir_node_by_def_id(parent) else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
|
||||||
|
let (trait_generics, trait_bounds) = match parent_trait.kind {
|
||||||
|
hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => (generics, supertraits),
|
||||||
|
hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Implicitly add `Self: DefaultAutoTrait` clauses on trait associated items if
|
||||||
|
// they are not added as super trait bounds to the trait itself. See comment on
|
||||||
|
// `requires_default_supertraits` for more details.
|
||||||
|
if !icx.lowerer().requires_default_supertraits(trait_bounds, trait_generics) {
|
||||||
|
let mut bounds = Vec::new();
|
||||||
|
let self_ty_where_predicates = (parent, item.generics.predicates);
|
||||||
|
icx.lowerer().add_default_traits_with_filter(
|
||||||
|
&mut bounds,
|
||||||
|
tcx.types.self_param,
|
||||||
|
&[],
|
||||||
|
Some(self_ty_where_predicates),
|
||||||
|
item.span,
|
||||||
|
|tr| tr != hir::LangItem::Sized,
|
||||||
|
);
|
||||||
|
predicates.extend(bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let generics = tcx.generics_of(def_id);
|
let generics = tcx.generics_of(def_id);
|
||||||
|
|
||||||
// Below we'll consider the bounds on the type parameters (including `Self`)
|
// Below we'll consider the bounds on the type parameters (including `Self`)
|
||||||
|
@ -181,11 +211,18 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||||
let mut bounds = Vec::new();
|
let mut bounds = Vec::new();
|
||||||
icx.lowerer().lower_bounds(
|
icx.lowerer().lower_bounds(
|
||||||
tcx.types.self_param,
|
tcx.types.self_param,
|
||||||
self_bounds,
|
self_bounds.0,
|
||||||
&mut bounds,
|
&mut bounds,
|
||||||
ty::List::empty(),
|
ty::List::empty(),
|
||||||
PredicateFilter::All,
|
PredicateFilter::All,
|
||||||
);
|
);
|
||||||
|
icx.lowerer().add_default_super_traits(
|
||||||
|
def_id,
|
||||||
|
&mut bounds,
|
||||||
|
self_bounds.0,
|
||||||
|
hir_generics,
|
||||||
|
self_bounds.1,
|
||||||
|
);
|
||||||
predicates.extend(bounds);
|
predicates.extend(bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,8 +247,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||||
GenericParamKind::Type { .. } => {
|
GenericParamKind::Type { .. } => {
|
||||||
let param_ty = icx.lowerer().lower_ty_param(param.hir_id);
|
let param_ty = icx.lowerer().lower_ty_param(param.hir_id);
|
||||||
let mut bounds = Vec::new();
|
let mut bounds = Vec::new();
|
||||||
// Params are implicitly sized unless a `?Sized` bound is found
|
// Implicit bounds are added to type params unless a `?Trait` bound is found
|
||||||
icx.lowerer().add_sized_bound(
|
icx.lowerer().add_default_traits(
|
||||||
&mut bounds,
|
&mut bounds,
|
||||||
param_ty,
|
param_ty,
|
||||||
&[],
|
&[],
|
||||||
|
@ -625,6 +662,22 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
|
||||||
let self_param_ty = tcx.types.self_param;
|
let self_param_ty = tcx.types.self_param;
|
||||||
let mut bounds = Vec::new();
|
let mut bounds = Vec::new();
|
||||||
icx.lowerer().lower_bounds(self_param_ty, superbounds, &mut bounds, ty::List::empty(), filter);
|
icx.lowerer().lower_bounds(self_param_ty, superbounds, &mut bounds, ty::List::empty(), filter);
|
||||||
|
match filter {
|
||||||
|
PredicateFilter::All
|
||||||
|
| PredicateFilter::SelfOnly
|
||||||
|
| PredicateFilter::SelfTraitThatDefines(_)
|
||||||
|
| PredicateFilter::SelfAndAssociatedTypeBounds => {
|
||||||
|
icx.lowerer().add_default_super_traits(
|
||||||
|
trait_def_id,
|
||||||
|
&mut bounds,
|
||||||
|
superbounds,
|
||||||
|
generics,
|
||||||
|
item.span,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
//`ConstIfConst` is only interested in `~const` bounds.
|
||||||
|
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
|
||||||
|
}
|
||||||
|
|
||||||
let where_bounds_that_match =
|
let where_bounds_that_match =
|
||||||
icx.probe_ty_param_bounds_in_generics(generics, item.owner_id.def_id, filter);
|
icx.probe_ty_param_bounds_in_generics(generics, item.owner_id.def_id, filter);
|
||||||
|
|
|
@ -4,9 +4,9 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||||
use rustc_errors::codes::*;
|
use rustc_errors::codes::*;
|
||||||
use rustc_errors::struct_span_code_err;
|
use rustc_errors::struct_span_code_err;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::HirId;
|
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
|
use rustc_hir::{AmbigArg, HirId};
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
||||||
|
@ -24,25 +24,190 @@ use crate::hir_ty_lowering::{
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
/// Add a `Sized` bound to the `bounds` if appropriate.
|
pub(crate) fn add_default_traits(
|
||||||
///
|
|
||||||
/// Doesn't add the bound if the HIR bounds contain any of `Sized`, `?Sized` or `!Sized`.
|
|
||||||
pub(crate) fn add_sized_bound(
|
|
||||||
&self,
|
&self,
|
||||||
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
hir_bounds: &'tcx [hir::GenericBound<'tcx>],
|
hir_bounds: &[hir::GenericBound<'tcx>],
|
||||||
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
|
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) {
|
) {
|
||||||
|
self.add_default_traits_with_filter(
|
||||||
|
bounds,
|
||||||
|
self_ty,
|
||||||
|
hir_bounds,
|
||||||
|
self_ty_where_predicates,
|
||||||
|
span,
|
||||||
|
|_| true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks whether `Self: DefaultAutoTrait` bounds should be added on trait super bounds
|
||||||
|
/// or associative items.
|
||||||
|
///
|
||||||
|
/// To keep backward compatibility with existing code, `experimental_default_bounds` bounds
|
||||||
|
/// should be added everywhere, including super bounds. However this causes a huge performance
|
||||||
|
/// costs. For optimization purposes instead of adding default supertraits, bounds
|
||||||
|
/// are added to the associative items:
|
||||||
|
///
|
||||||
|
/// ```ignore(illustrative)
|
||||||
|
/// // Default bounds are generated in the following way:
|
||||||
|
/// trait Trait {
|
||||||
|
/// fn foo(&self) where Self: Leak {}
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // instead of this:
|
||||||
|
/// trait Trait: Leak {
|
||||||
|
/// fn foo(&self) {}
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// It is not always possible to do this because of backward compatibility:
|
||||||
|
///
|
||||||
|
/// ```ignore(illustrative)
|
||||||
|
/// pub trait Trait<Rhs = Self> {}
|
||||||
|
/// pub trait Trait1 : Trait {}
|
||||||
|
/// //~^ ERROR: `Rhs` requires `DefaultAutoTrait`, but `Self` is not `DefaultAutoTrait`
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// or:
|
||||||
|
///
|
||||||
|
/// ```ignore(illustrative)
|
||||||
|
/// trait Trait {
|
||||||
|
/// type Type where Self: Sized;
|
||||||
|
/// }
|
||||||
|
/// trait Trait2<T> : Trait<Type = T> {}
|
||||||
|
/// //~^ ERROR: `DefaultAutoTrait` required for `Trait2`, by implicit `Self: DefaultAutoTrait` in `Trait::Type`
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Therefore, `experimental_default_bounds` are still being added to supertraits if
|
||||||
|
/// the `SelfTyParam` or `AssocItemConstraint` were found in a trait header.
|
||||||
|
pub(crate) fn requires_default_supertraits(
|
||||||
|
&self,
|
||||||
|
hir_bounds: &'tcx [hir::GenericBound<'tcx>],
|
||||||
|
hir_generics: &'tcx hir::Generics<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
struct TraitInfoCollector;
|
||||||
|
|
||||||
|
impl<'tcx> hir::intravisit::Visitor<'tcx> for TraitInfoCollector {
|
||||||
|
type Result = ControlFlow<()>;
|
||||||
|
|
||||||
|
fn visit_assoc_item_constraint(
|
||||||
|
&mut self,
|
||||||
|
_constraint: &'tcx hir::AssocItemConstraint<'tcx>,
|
||||||
|
) -> Self::Result {
|
||||||
|
ControlFlow::Break(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
|
||||||
|
if matches!(
|
||||||
|
&t.kind,
|
||||||
|
hir::TyKind::Path(hir::QPath::Resolved(
|
||||||
|
_,
|
||||||
|
hir::Path { res: hir::def::Res::SelfTyParam { .. }, .. },
|
||||||
|
))
|
||||||
|
) {
|
||||||
|
return ControlFlow::Break(());
|
||||||
|
}
|
||||||
|
hir::intravisit::walk_ty(self, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut found = false;
|
||||||
|
for bound in hir_bounds {
|
||||||
|
found |= hir::intravisit::walk_param_bound(&mut TraitInfoCollector, bound).is_break();
|
||||||
|
}
|
||||||
|
found |= hir::intravisit::walk_generics(&mut TraitInfoCollector, hir_generics).is_break();
|
||||||
|
found
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lazily sets `experimental_default_bounds` to true on trait super bounds.
|
||||||
|
/// See `requires_default_supertraits` for more information.
|
||||||
|
pub(crate) fn add_default_super_traits(
|
||||||
|
&self,
|
||||||
|
trait_def_id: LocalDefId,
|
||||||
|
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||||
|
hir_bounds: &'tcx [hir::GenericBound<'tcx>],
|
||||||
|
hir_generics: &'tcx hir::Generics<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
) {
|
||||||
|
assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias));
|
||||||
|
if self.requires_default_supertraits(hir_bounds, hir_generics) {
|
||||||
|
let self_ty_where_predicates = (trait_def_id, hir_generics.predicates);
|
||||||
|
self.add_default_traits_with_filter(
|
||||||
|
bounds,
|
||||||
|
self.tcx().types.self_param,
|
||||||
|
hir_bounds,
|
||||||
|
Some(self_ty_where_predicates),
|
||||||
|
span,
|
||||||
|
|default_trait| default_trait != hir::LangItem::Sized,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_default_traits_with_filter(
|
||||||
|
&self,
|
||||||
|
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||||
|
self_ty: Ty<'tcx>,
|
||||||
|
hir_bounds: &[hir::GenericBound<'tcx>],
|
||||||
|
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
|
||||||
|
span: Span,
|
||||||
|
f: impl Fn(hir::LangItem) -> bool,
|
||||||
|
) {
|
||||||
|
self.tcx().default_traits().iter().filter(|&&default_trait| f(default_trait)).for_each(
|
||||||
|
|default_trait| {
|
||||||
|
self.add_default_trait(
|
||||||
|
*default_trait,
|
||||||
|
bounds,
|
||||||
|
self_ty,
|
||||||
|
hir_bounds,
|
||||||
|
self_ty_where_predicates,
|
||||||
|
span,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a `Sized` or `experimental_default_bounds` bounds to the `bounds` if appropriate.
|
||||||
|
///
|
||||||
|
/// Doesn't add the bound if the HIR bounds contain any of `Trait`, `?Trait` or `!Trait`.
|
||||||
|
pub(crate) fn add_default_trait(
|
||||||
|
&self,
|
||||||
|
trait_: hir::LangItem,
|
||||||
|
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||||
|
self_ty: Ty<'tcx>,
|
||||||
|
hir_bounds: &[hir::GenericBound<'tcx>],
|
||||||
|
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
|
||||||
|
span: Span,
|
||||||
|
) {
|
||||||
|
let trait_id = self.tcx().lang_items().get(trait_);
|
||||||
|
if let Some(trait_id) = trait_id
|
||||||
|
&& self.do_not_provide_default_trait_bound(
|
||||||
|
trait_id,
|
||||||
|
hir_bounds,
|
||||||
|
self_ty_where_predicates,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// There was no `?Trait` or `!Trait` bound;
|
||||||
|
// add `Trait` if it's available.
|
||||||
|
let trait_ref = ty::TraitRef::new(self.tcx(), trait_id, [self_ty]);
|
||||||
|
// Preferable to put this obligation first, since we report better errors for sized ambiguity.
|
||||||
|
bounds.insert(0, (trait_ref.upcast(self.tcx()), span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_not_provide_default_trait_bound<'a>(
|
||||||
|
&self,
|
||||||
|
trait_def_id: DefId,
|
||||||
|
hir_bounds: &'a [hir::GenericBound<'tcx>],
|
||||||
|
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
|
||||||
|
) -> bool {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let sized_def_id = tcx.lang_items().sized_trait();
|
let mut seen_negative_bound = false;
|
||||||
let mut seen_negative_sized_bound = false;
|
let mut seen_positive_bound = false;
|
||||||
let mut seen_positive_sized_bound = false;
|
|
||||||
|
|
||||||
// Try to find an unbound in bounds.
|
// Try to find an unbound in bounds.
|
||||||
let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
|
let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
|
||||||
let mut search_bounds = |hir_bounds: &'tcx [hir::GenericBound<'tcx>]| {
|
let mut search_bounds = |hir_bounds: &'a [hir::GenericBound<'tcx>]| {
|
||||||
for hir_bound in hir_bounds {
|
for hir_bound in hir_bounds {
|
||||||
let hir::GenericBound::Trait(ptr) = hir_bound else {
|
let hir::GenericBound::Trait(ptr) = hir_bound else {
|
||||||
continue;
|
continue;
|
||||||
|
@ -50,17 +215,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
match ptr.modifiers.polarity {
|
match ptr.modifiers.polarity {
|
||||||
hir::BoundPolarity::Maybe(_) => unbounds.push(ptr),
|
hir::BoundPolarity::Maybe(_) => unbounds.push(ptr),
|
||||||
hir::BoundPolarity::Negative(_) => {
|
hir::BoundPolarity::Negative(_) => {
|
||||||
if let Some(sized_def_id) = sized_def_id
|
if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) {
|
||||||
&& ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
|
seen_negative_bound = true;
|
||||||
{
|
|
||||||
seen_negative_sized_bound = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::BoundPolarity::Positive => {
|
hir::BoundPolarity::Positive => {
|
||||||
if let Some(sized_def_id) = sized_def_id
|
if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) {
|
||||||
&& ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
|
seen_positive_bound = true;
|
||||||
{
|
|
||||||
seen_positive_sized_bound = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,32 +256,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut seen_sized_unbound = false;
|
let mut seen_unbound = false;
|
||||||
for unbound in unbounds {
|
for unbound in unbounds {
|
||||||
if let Some(sized_def_id) = sized_def_id
|
let unbound_def_id = unbound.trait_ref.trait_def_id();
|
||||||
&& unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
|
if unbound_def_id == Some(trait_def_id) {
|
||||||
{
|
seen_unbound = true;
|
||||||
seen_sized_unbound = true;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
// There was a `?Trait` bound, but it was not `?Sized`
|
let emit_relax_err = || {
|
||||||
self.dcx().span_err(
|
let unbound_traits =
|
||||||
|
match self.tcx().sess.opts.unstable_opts.experimental_default_bounds {
|
||||||
|
true => "`?Sized` and `experimental_default_bounds`",
|
||||||
|
false => "`?Sized`",
|
||||||
|
};
|
||||||
|
// There was a `?Trait` bound, but it was neither `?Sized` nor `experimental_default_bounds`.
|
||||||
|
tcx.dcx().span_err(
|
||||||
unbound.span,
|
unbound.span,
|
||||||
"relaxing a default bound only does something for `?Sized`; \
|
format!(
|
||||||
|
"relaxing a default bound only does something for {}; \
|
||||||
all other traits are not bound by default",
|
all other traits are not bound by default",
|
||||||
|
unbound_traits
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
match unbound_def_id {
|
||||||
|
Some(def_id) if !tcx.is_default_trait(def_id) => emit_relax_err(),
|
||||||
|
None => emit_relax_err(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if seen_sized_unbound || seen_negative_sized_bound || seen_positive_sized_bound {
|
!(seen_unbound || seen_negative_bound || seen_positive_bound)
|
||||||
// There was in fact a `?Sized`, `!Sized` or explicit `Sized` bound;
|
|
||||||
// we don't need to do anything.
|
|
||||||
} else if let Some(sized_def_id) = sized_def_id {
|
|
||||||
// There was no `?Sized`, `!Sized` or explicit `Sized` bound;
|
|
||||||
// add `Sized` if it's available.
|
|
||||||
let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [self_ty]);
|
|
||||||
// Preferable to put this obligation first, since we report better errors for sized ambiguity.
|
|
||||||
bounds.insert(0, (trait_ref.upcast(tcx), span));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any.
|
/// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any.
|
||||||
|
|
|
@ -57,6 +57,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ast_bounds: Vec<_> =
|
||||||
|
hir_bounds.iter().map(|&trait_ref| hir::GenericBound::Trait(trait_ref)).collect();
|
||||||
|
|
||||||
|
self.add_default_traits_with_filter(
|
||||||
|
&mut user_written_bounds,
|
||||||
|
dummy_self,
|
||||||
|
&ast_bounds,
|
||||||
|
None,
|
||||||
|
span,
|
||||||
|
|tr| tr != hir::LangItem::Sized,
|
||||||
|
);
|
||||||
|
|
||||||
let (elaborated_trait_bounds, elaborated_projection_bounds) =
|
let (elaborated_trait_bounds, elaborated_projection_bounds) =
|
||||||
traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
|
traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
|
||||||
let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds
|
let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds
|
||||||
|
|
|
@ -446,6 +446,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||||
self.is_lang_item(def_id, trait_lang_item_to_lang_item(lang_item))
|
self.is_lang_item(def_id, trait_lang_item_to_lang_item(lang_item))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_default_trait(self, def_id: DefId) -> bool {
|
||||||
|
self.is_default_trait(def_id)
|
||||||
|
}
|
||||||
|
|
||||||
fn as_lang_item(self, def_id: DefId) -> Option<TraitSolverLangItem> {
|
fn as_lang_item(self, def_id: DefId) -> Option<TraitSolverLangItem> {
|
||||||
lang_item_to_trait_lang_item(self.lang_items().from_def_id(def_id)?)
|
lang_item_to_trait_lang_item(self.lang_items().from_def_id(def_id)?)
|
||||||
}
|
}
|
||||||
|
@ -1539,6 +1543,25 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
self.reserve_and_set_memory_dedup(alloc, salt)
|
self.reserve_and_set_memory_dedup(alloc, salt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn default_traits(self) -> &'static [rustc_hir::LangItem] {
|
||||||
|
match self.sess.opts.unstable_opts.experimental_default_bounds {
|
||||||
|
true => &[
|
||||||
|
LangItem::Sized,
|
||||||
|
LangItem::DefaultTrait1,
|
||||||
|
LangItem::DefaultTrait2,
|
||||||
|
LangItem::DefaultTrait3,
|
||||||
|
LangItem::DefaultTrait4,
|
||||||
|
],
|
||||||
|
false => &[LangItem::Sized],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_default_trait(self, def_id: DefId) -> bool {
|
||||||
|
self.default_traits()
|
||||||
|
.iter()
|
||||||
|
.any(|&default_trait| self.lang_items().get(default_trait) == Some(def_id))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a range of the start/end indices specified with the
|
/// Returns a range of the start/end indices specified with the
|
||||||
/// `rustc_layout_scalar_valid_range` attribute.
|
/// `rustc_layout_scalar_valid_range` attribute.
|
||||||
// FIXME(eddyb) this is an awkward spot for this method, maybe move it?
|
// FIXME(eddyb) this is an awkward spot for this method, maybe move it?
|
||||||
|
|
|
@ -37,12 +37,16 @@ where
|
||||||
| ty::Never
|
| ty::Never
|
||||||
| ty::Char => Ok(ty::Binder::dummy(vec![])),
|
| ty::Char => Ok(ty::Binder::dummy(vec![])),
|
||||||
|
|
||||||
|
// This branch is only for `experimental_default_bounds`.
|
||||||
|
// Other foreign types were rejected earlier in
|
||||||
|
// `disqualify_auto_trait_candidate_due_to_possible_impl`.
|
||||||
|
ty::Foreign(..) => Ok(ty::Binder::dummy(vec![])),
|
||||||
|
|
||||||
// Treat `str` like it's defined as `struct str([u8]);`
|
// Treat `str` like it's defined as `struct str([u8]);`
|
||||||
ty::Str => Ok(ty::Binder::dummy(vec![Ty::new_slice(cx, Ty::new_u8(cx))])),
|
ty::Str => Ok(ty::Binder::dummy(vec![Ty::new_slice(cx, Ty::new_u8(cx))])),
|
||||||
|
|
||||||
ty::Dynamic(..)
|
ty::Dynamic(..)
|
||||||
| ty::Param(..)
|
| ty::Param(..)
|
||||||
| ty::Foreign(..)
|
|
||||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
|
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
|
||||||
| ty::Placeholder(..)
|
| ty::Placeholder(..)
|
||||||
| ty::Bound(..)
|
| ty::Bound(..)
|
||||||
|
|
|
@ -1086,6 +1086,25 @@ where
|
||||||
goal: Goal<I, TraitPredicate<I>>,
|
goal: Goal<I, TraitPredicate<I>>,
|
||||||
) -> Option<Result<Candidate<I>, NoSolution>> {
|
) -> Option<Result<Candidate<I>, NoSolution>> {
|
||||||
let self_ty = goal.predicate.self_ty();
|
let self_ty = goal.predicate.self_ty();
|
||||||
|
let check_impls = || {
|
||||||
|
let mut disqualifying_impl = None;
|
||||||
|
self.cx().for_each_relevant_impl(
|
||||||
|
goal.predicate.def_id(),
|
||||||
|
goal.predicate.self_ty(),
|
||||||
|
|impl_def_id| {
|
||||||
|
disqualifying_impl = Some(impl_def_id);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if let Some(def_id) = disqualifying_impl {
|
||||||
|
trace!(?def_id, ?goal, "disqualified auto-trait implementation");
|
||||||
|
// No need to actually consider the candidate here,
|
||||||
|
// since we do that in `consider_impl_candidate`.
|
||||||
|
return Some(Err(NoSolution));
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match self_ty.kind() {
|
match self_ty.kind() {
|
||||||
// Stall int and float vars until they are resolved to a concrete
|
// Stall int and float vars until they are resolved to a concrete
|
||||||
// numerical type. That's because the check for impls below treats
|
// numerical type. That's because the check for impls below treats
|
||||||
|
@ -1096,6 +1115,10 @@ where
|
||||||
Some(self.forced_ambiguity(MaybeCause::Ambiguity))
|
Some(self.forced_ambiguity(MaybeCause::Ambiguity))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Backward compatibility for default auto traits.
|
||||||
|
// Test: ui/traits/default_auto_traits/extern-types.rs
|
||||||
|
ty::Foreign(..) if self.cx().is_default_trait(goal.predicate.def_id()) => check_impls(),
|
||||||
|
|
||||||
// These types cannot be structurally decomposed into constituent
|
// These types cannot be structurally decomposed into constituent
|
||||||
// types, and therefore have no built-in auto impl.
|
// types, and therefore have no built-in auto impl.
|
||||||
ty::Dynamic(..)
|
ty::Dynamic(..)
|
||||||
|
@ -1156,24 +1179,7 @@ where
|
||||||
| ty::Never
|
| ty::Never
|
||||||
| ty::Tuple(_)
|
| ty::Tuple(_)
|
||||||
| ty::Adt(_, _)
|
| ty::Adt(_, _)
|
||||||
| ty::UnsafeBinder(_) => {
|
| ty::UnsafeBinder(_) => check_impls(),
|
||||||
let mut disqualifying_impl = None;
|
|
||||||
self.cx().for_each_relevant_impl(
|
|
||||||
goal.predicate.def_id(),
|
|
||||||
goal.predicate.self_ty(),
|
|
||||||
|impl_def_id| {
|
|
||||||
disqualifying_impl = Some(impl_def_id);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
if let Some(def_id) = disqualifying_impl {
|
|
||||||
trace!(?def_id, ?goal, "disqualified auto-trait implementation");
|
|
||||||
// No need to actually consider the candidate here,
|
|
||||||
// since we do that in `consider_impl_candidate`.
|
|
||||||
return Some(Err(NoSolution));
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ty::Error(_) => None,
|
ty::Error(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2187,6 +2187,8 @@ options! {
|
||||||
"Use WebAssembly error handling for wasm32-unknown-emscripten"),
|
"Use WebAssembly error handling for wasm32-unknown-emscripten"),
|
||||||
enforce_type_length_limit: bool = (false, parse_bool, [TRACKED],
|
enforce_type_length_limit: bool = (false, parse_bool, [TRACKED],
|
||||||
"enforce the type length limit when monomorphizing instances in codegen"),
|
"enforce the type length limit when monomorphizing instances in codegen"),
|
||||||
|
experimental_default_bounds: bool = (false, parse_bool, [TRACKED],
|
||||||
|
"enable default bounds for experimental group of auto traits"),
|
||||||
export_executable_symbols: bool = (false, parse_bool, [TRACKED],
|
export_executable_symbols: bool = (false, parse_bool, [TRACKED],
|
||||||
"export symbols from executables, as if they were dynamic libraries"),
|
"export symbols from executables, as if they were dynamic libraries"),
|
||||||
external_clangrt: bool = (false, parse_bool, [UNTRACKED],
|
external_clangrt: bool = (false, parse_bool, [UNTRACKED],
|
||||||
|
|
|
@ -800,6 +800,15 @@ symbols! {
|
||||||
default_fn,
|
default_fn,
|
||||||
default_lib_allocator,
|
default_lib_allocator,
|
||||||
default_method_body_is_const,
|
default_method_body_is_const,
|
||||||
|
// --------------------------
|
||||||
|
// Lang items which are used only for experiments with auto traits with default bounds.
|
||||||
|
// These lang items are not actually defined in core/std. Experiment is a part of
|
||||||
|
// `MCP: Low level components for async drop`(https://github.com/rust-lang/compiler-team/issues/727)
|
||||||
|
default_trait1,
|
||||||
|
default_trait2,
|
||||||
|
default_trait3,
|
||||||
|
default_trait4,
|
||||||
|
// --------------------------
|
||||||
default_type_parameter_fallback,
|
default_type_parameter_fallback,
|
||||||
default_type_params,
|
default_type_params,
|
||||||
define_opaque,
|
define_opaque,
|
||||||
|
|
|
@ -692,6 +692,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
|
|
||||||
let def_id = obligation.predicate.def_id();
|
let def_id = obligation.predicate.def_id();
|
||||||
|
|
||||||
|
let mut check_impls = || {
|
||||||
|
// Only consider auto impls if there are no manual impls for the root of `self_ty`.
|
||||||
|
//
|
||||||
|
// For example, we only consider auto candidates for `&i32: Auto` if no explicit impl
|
||||||
|
// for `&SomeType: Auto` exists. Due to E0321 the only crate where impls
|
||||||
|
// for `&SomeType: Auto` can be defined is the crate where `Auto` has been defined.
|
||||||
|
//
|
||||||
|
// Generally, we have to guarantee that for all `SimplifiedType`s the only crate
|
||||||
|
// which may define impls for that type is either the crate defining the type
|
||||||
|
// or the trait. This should be guaranteed by the orphan check.
|
||||||
|
let mut has_impl = false;
|
||||||
|
self.tcx().for_each_relevant_impl(def_id, self_ty, |_| has_impl = true);
|
||||||
|
if !has_impl {
|
||||||
|
candidates.vec.push(AutoImplCandidate)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if self.tcx().trait_is_auto(def_id) {
|
if self.tcx().trait_is_auto(def_id) {
|
||||||
match *self_ty.kind() {
|
match *self_ty.kind() {
|
||||||
ty::Dynamic(..) => {
|
ty::Dynamic(..) => {
|
||||||
|
@ -705,6 +722,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// we don't add any `..` impl. Default traits could
|
// we don't add any `..` impl. Default traits could
|
||||||
// still be provided by a manual implementation for
|
// still be provided by a manual implementation for
|
||||||
// this trait and type.
|
// this trait and type.
|
||||||
|
|
||||||
|
// Backward compatibility for default auto traits.
|
||||||
|
// Test: ui/traits/default_auto_traits/extern-types.rs
|
||||||
|
if self.tcx().is_default_trait(def_id) {
|
||||||
|
check_impls()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ty::Param(..)
|
ty::Param(..)
|
||||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
|
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
|
||||||
|
@ -805,20 +828,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only consider auto impls if there are no manual impls for the root of `self_ty`.
|
check_impls();
|
||||||
//
|
|
||||||
// For example, we only consider auto candidates for `&i32: Auto` if no explicit impl
|
|
||||||
// for `&SomeType: Auto` exists. Due to E0321 the only crate where impls
|
|
||||||
// for `&SomeType: Auto` can be defined is the crate where `Auto` has been defined.
|
|
||||||
//
|
|
||||||
// Generally, we have to guarantee that for all `SimplifiedType`s the only crate
|
|
||||||
// which may define impls for that type is either the crate defining the type
|
|
||||||
// or the trait. This should be guaranteed by the orphan check.
|
|
||||||
let mut has_impl = false;
|
|
||||||
self.tcx().for_each_relevant_impl(def_id, self_ty, |_| has_impl = true);
|
|
||||||
if !has_impl {
|
|
||||||
candidates.vec.push(AutoImplCandidate)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ty::Error(_) => {
|
ty::Error(_) => {
|
||||||
candidates.vec.push(AutoImplCandidate);
|
candidates.vec.push(AutoImplCandidate);
|
||||||
|
|
|
@ -2299,6 +2299,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||||
| ty::Never
|
| ty::Never
|
||||||
| ty::Char => ty::Binder::dummy(Vec::new()),
|
| ty::Char => ty::Binder::dummy(Vec::new()),
|
||||||
|
|
||||||
|
// This branch is only for `experimental_default_bounds`.
|
||||||
|
// Other foreign types were rejected earlier in
|
||||||
|
// `assemble_candidates_from_auto_impls`.
|
||||||
|
ty::Foreign(..) => ty::Binder::dummy(Vec::new()),
|
||||||
|
|
||||||
// FIXME(unsafe_binders): Squash the double binder for now, I guess.
|
// FIXME(unsafe_binders): Squash the double binder for now, I guess.
|
||||||
ty::UnsafeBinder(_) => return Err(SelectionError::Unimplemented),
|
ty::UnsafeBinder(_) => return Err(SelectionError::Unimplemented),
|
||||||
|
|
||||||
|
@ -2308,7 +2313,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||||
ty::Placeholder(..)
|
ty::Placeholder(..)
|
||||||
| ty::Dynamic(..)
|
| ty::Dynamic(..)
|
||||||
| ty::Param(..)
|
| ty::Param(..)
|
||||||
| ty::Foreign(..)
|
|
||||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
|
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
|
||||||
| ty::Bound(..)
|
| ty::Bound(..)
|
||||||
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
||||||
|
|
|
@ -259,6 +259,8 @@ pub trait Interner:
|
||||||
|
|
||||||
fn is_lang_item(self, def_id: Self::DefId, lang_item: TraitSolverLangItem) -> bool;
|
fn is_lang_item(self, def_id: Self::DefId, lang_item: TraitSolverLangItem) -> bool;
|
||||||
|
|
||||||
|
fn is_default_trait(self, def_id: Self::DefId) -> bool;
|
||||||
|
|
||||||
fn as_lang_item(self, def_id: Self::DefId) -> Option<TraitSolverLangItem>;
|
fn as_lang_item(self, def_id: Self::DefId) -> Option<TraitSolverLangItem>;
|
||||||
|
|
||||||
fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator<Item = Self::DefId>;
|
fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator<Item = Self::DefId>;
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
//@ check-pass
|
||||||
|
//@ compile-flags: -Zexperimental-default-bounds
|
||||||
|
|
||||||
|
#![feature(auto_traits, lang_items, no_core, rustc_attrs, trait_alias)]
|
||||||
|
#![no_std]
|
||||||
|
#![no_core]
|
||||||
|
|
||||||
|
#[lang = "sized"]
|
||||||
|
trait Sized {}
|
||||||
|
|
||||||
|
#[lang = "default_trait1"]
|
||||||
|
auto trait DefaultTrait1 {}
|
||||||
|
|
||||||
|
#[lang = "default_trait2"]
|
||||||
|
auto trait DefaultTrait2 {}
|
||||||
|
|
||||||
|
trait Trait<Rhs: ?Sized = Self> {}
|
||||||
|
trait Trait1 : Trait {}
|
||||||
|
|
||||||
|
trait Trait2 {
|
||||||
|
type Type;
|
||||||
|
}
|
||||||
|
trait Trait3<T> = Trait2<Type = T>;
|
||||||
|
|
||||||
|
fn main() {}
|
41
tests/ui/traits/default_auto_traits/default-bounds.rs
Normal file
41
tests/ui/traits/default_auto_traits/default-bounds.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
//@ compile-flags: -Zexperimental-default-bounds
|
||||||
|
|
||||||
|
#![feature(
|
||||||
|
auto_traits,
|
||||||
|
lang_items,
|
||||||
|
negative_impls,
|
||||||
|
no_core,
|
||||||
|
rustc_attrs
|
||||||
|
)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![no_std]
|
||||||
|
#![no_core]
|
||||||
|
|
||||||
|
#[lang = "sized"]
|
||||||
|
trait Sized {}
|
||||||
|
|
||||||
|
#[lang = "copy"]
|
||||||
|
pub trait Copy {}
|
||||||
|
|
||||||
|
#[lang = "default_trait1"]
|
||||||
|
auto trait Leak {}
|
||||||
|
|
||||||
|
#[lang = "default_trait2"]
|
||||||
|
auto trait SyncDrop {}
|
||||||
|
|
||||||
|
struct Forbidden;
|
||||||
|
|
||||||
|
impl !Leak for Forbidden {}
|
||||||
|
impl !SyncDrop for Forbidden {}
|
||||||
|
|
||||||
|
struct Accepted;
|
||||||
|
|
||||||
|
fn bar<T: Leak>(_: T) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// checking that bounds can be added explicitly
|
||||||
|
bar(Forbidden);
|
||||||
|
//~^ ERROR the trait bound `Forbidden: Leak` is not satisfied
|
||||||
|
//~| ERROR the trait bound `Forbidden: SyncDrop` is not satisfied
|
||||||
|
bar(Accepted);
|
||||||
|
}
|
31
tests/ui/traits/default_auto_traits/default-bounds.stderr
Normal file
31
tests/ui/traits/default_auto_traits/default-bounds.stderr
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
error[E0277]: the trait bound `Forbidden: SyncDrop` is not satisfied
|
||||||
|
--> $DIR/default-bounds.rs:37:9
|
||||||
|
|
|
||||||
|
LL | bar(Forbidden);
|
||||||
|
| --- ^^^^^^^^^ the trait `SyncDrop` is not implemented for `Forbidden`
|
||||||
|
| |
|
||||||
|
| required by a bound introduced by this call
|
||||||
|
|
|
||||||
|
note: required by a bound in `bar`
|
||||||
|
--> $DIR/default-bounds.rs:33:8
|
||||||
|
|
|
||||||
|
LL | fn bar<T: Leak>(_: T) {}
|
||||||
|
| ^ required by this bound in `bar`
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `Forbidden: Leak` is not satisfied
|
||||||
|
--> $DIR/default-bounds.rs:37:9
|
||||||
|
|
|
||||||
|
LL | bar(Forbidden);
|
||||||
|
| --- ^^^^^^^^^ the trait `Leak` is not implemented for `Forbidden`
|
||||||
|
| |
|
||||||
|
| required by a bound introduced by this call
|
||||||
|
|
|
||||||
|
note: required by a bound in `bar`
|
||||||
|
--> $DIR/default-bounds.rs:33:11
|
||||||
|
|
|
||||||
|
LL | fn bar<T: Leak>(_: T) {}
|
||||||
|
| ^^^^ required by this bound in `bar`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
|
@ -0,0 +1,17 @@
|
||||||
|
error[E0277]: the trait bound `extern_non_leak::Opaque: Leak` is not satisfied
|
||||||
|
--> $DIR/extern-types.rs:44:13
|
||||||
|
|
|
||||||
|
LL | foo(x);
|
||||||
|
| --- ^ the trait `Leak` is not implemented for `extern_non_leak::Opaque`
|
||||||
|
| |
|
||||||
|
| required by a bound introduced by this call
|
||||||
|
|
|
||||||
|
note: required by a bound in `foo`
|
||||||
|
--> $DIR/extern-types.rs:20:8
|
||||||
|
|
|
||||||
|
LL | fn foo<T: ?Sized>(_: &T) {}
|
||||||
|
| ^ required by this bound in `foo`
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
17
tests/ui/traits/default_auto_traits/extern-types.next.stderr
Normal file
17
tests/ui/traits/default_auto_traits/extern-types.next.stderr
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
error[E0277]: the trait bound `extern_non_leak::Opaque: Leak` is not satisfied
|
||||||
|
--> $DIR/extern-types.rs:44:13
|
||||||
|
|
|
||||||
|
LL | foo(x);
|
||||||
|
| --- ^ the trait `Leak` is not implemented for `extern_non_leak::Opaque`
|
||||||
|
| |
|
||||||
|
| required by a bound introduced by this call
|
||||||
|
|
|
||||||
|
note: required by a bound in `foo`
|
||||||
|
--> $DIR/extern-types.rs:20:8
|
||||||
|
|
|
||||||
|
LL | fn foo<T: ?Sized>(_: &T) {}
|
||||||
|
| ^ required by this bound in `foo`
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
49
tests/ui/traits/default_auto_traits/extern-types.rs
Normal file
49
tests/ui/traits/default_auto_traits/extern-types.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
//@ compile-flags: -Zexperimental-default-bounds
|
||||||
|
//@ revisions: current next
|
||||||
|
//@ [next] compile-flags: -Znext-solver
|
||||||
|
|
||||||
|
#![feature(auto_traits, extern_types, lang_items, negative_impls, no_core, rustc_attrs)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![no_std]
|
||||||
|
#![no_core]
|
||||||
|
|
||||||
|
#[lang = "sized"]
|
||||||
|
trait Sized {}
|
||||||
|
|
||||||
|
#[lang = "copy"]
|
||||||
|
pub trait Copy {}
|
||||||
|
|
||||||
|
#[lang = "default_trait1"]
|
||||||
|
auto trait Leak {}
|
||||||
|
|
||||||
|
// implicit T: Leak here
|
||||||
|
fn foo<T: ?Sized>(_: &T) {}
|
||||||
|
|
||||||
|
mod extern_leak {
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
type Opaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn forward_extern_ty(x: &Opaque) {
|
||||||
|
// ok, extern type leak by default
|
||||||
|
crate::foo(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod extern_non_leak {
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
type Opaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl !Leak for Opaque {}
|
||||||
|
fn forward_extern_ty(x: &Opaque) {
|
||||||
|
foo(x);
|
||||||
|
//~^ ERROR: the trait bound `extern_non_leak::Opaque: Leak` is not satisfied
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,61 @@
|
||||||
|
//@ compile-flags: -Zexperimental-default-bounds
|
||||||
|
|
||||||
|
#![feature(
|
||||||
|
auto_traits,
|
||||||
|
lang_items,
|
||||||
|
more_maybe_bounds,
|
||||||
|
negative_impls,
|
||||||
|
no_core,
|
||||||
|
rustc_attrs
|
||||||
|
)]
|
||||||
|
#![allow(internal_features)]
|
||||||
|
#![no_std]
|
||||||
|
#![no_core]
|
||||||
|
|
||||||
|
#[lang = "sized"]
|
||||||
|
trait Sized {}
|
||||||
|
|
||||||
|
#[lang = "copy"]
|
||||||
|
pub trait Copy {}
|
||||||
|
impl<'a, T: ?Sized> Copy for &'a T {}
|
||||||
|
|
||||||
|
#[lang = "legacy_receiver"]
|
||||||
|
trait Receiver {}
|
||||||
|
impl<T: ?Sized + ?Leak> Receiver for &T {}
|
||||||
|
|
||||||
|
#[lang = "unsize"]
|
||||||
|
trait Unsize<T: ?Sized + ?Leak> {}
|
||||||
|
|
||||||
|
#[lang = "coerce_unsized"]
|
||||||
|
trait CoerceUnsized<T: ?Leak + ?Sized> {}
|
||||||
|
impl<'a, 'b: 'a, T: ?Sized + ?Leak + Unsize<U>, U: ?Sized + ?Leak> CoerceUnsized<&'a U> for &'b T {}
|
||||||
|
|
||||||
|
#[lang = "dispatch_from_dyn"]
|
||||||
|
trait DispatchFromDyn<T: ?Leak> {}
|
||||||
|
impl<'a, T: ?Sized + ?Leak + Unsize<U>, U: ?Sized + ?Leak> DispatchFromDyn<&'a U> for &'a T {}
|
||||||
|
|
||||||
|
#[lang = "default_trait1"]
|
||||||
|
auto trait Leak {}
|
||||||
|
|
||||||
|
struct NonLeakS;
|
||||||
|
impl !Leak for NonLeakS {}
|
||||||
|
struct LeakS;
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
fn leak_foo(&self) {}
|
||||||
|
fn maybe_leak_foo(&self) where Self: ?Leak {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for NonLeakS {}
|
||||||
|
impl Trait for LeakS {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _: &dyn Trait = &NonLeakS;
|
||||||
|
//~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied
|
||||||
|
let _: &dyn Trait = &LeakS;
|
||||||
|
let _: &(dyn Trait + ?Leak) = &LeakS;
|
||||||
|
let x: &(dyn Trait + ?Leak) = &NonLeakS;
|
||||||
|
x.leak_foo();
|
||||||
|
//~^ ERROR the trait bound `dyn Trait: Leak` is not satisfied
|
||||||
|
x.maybe_leak_foo();
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied
|
||||||
|
--> $DIR/maybe-bounds-in-dyn-traits.rs:53:25
|
||||||
|
|
|
||||||
|
LL | let _: &dyn Trait = &NonLeakS;
|
||||||
|
| ^^^^^^^^^ the trait `Leak` is not implemented for `NonLeakS`
|
||||||
|
|
|
||||||
|
= note: required for the cast from `&NonLeakS` to `&dyn Trait + Leak`
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `dyn Trait: Leak` is not satisfied
|
||||||
|
--> $DIR/maybe-bounds-in-dyn-traits.rs:58:7
|
||||||
|
|
|
||||||
|
LL | x.leak_foo();
|
||||||
|
| ^^^^^^^^ the trait `Leak` is not implemented for `dyn Trait`
|
||||||
|
|
|
||||||
|
note: required by a bound in `Trait::leak_foo`
|
||||||
|
--> $DIR/maybe-bounds-in-dyn-traits.rs:45:5
|
||||||
|
|
|
||||||
|
LL | fn leak_foo(&self) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::leak_foo`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
115
tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs
Normal file
115
tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
//@ compile-flags: -Zexperimental-default-bounds
|
||||||
|
|
||||||
|
#![feature(
|
||||||
|
auto_traits,
|
||||||
|
associated_type_defaults,
|
||||||
|
generic_const_items,
|
||||||
|
lang_items,
|
||||||
|
more_maybe_bounds,
|
||||||
|
negative_impls,
|
||||||
|
no_core,
|
||||||
|
rustc_attrs
|
||||||
|
)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![no_std]
|
||||||
|
#![no_core]
|
||||||
|
|
||||||
|
#[lang = "sized"]
|
||||||
|
trait Sized {}
|
||||||
|
|
||||||
|
#[lang = "legacy_receiver"]
|
||||||
|
trait LegacyReceiver {}
|
||||||
|
impl<T: ?Sized + ?Leak> LegacyReceiver for &T {}
|
||||||
|
impl<T: ?Sized> LegacyReceiver for &mut T {}
|
||||||
|
|
||||||
|
#[lang = "default_trait1"]
|
||||||
|
auto trait Leak {}
|
||||||
|
|
||||||
|
struct NonLeakS;
|
||||||
|
impl !Leak for NonLeakS {}
|
||||||
|
struct LeakS;
|
||||||
|
|
||||||
|
mod supertraits {
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
trait MaybeLeakT1: ?Leak {}
|
||||||
|
trait MaybeLeakT2 where Self: ?Leak {}
|
||||||
|
|
||||||
|
impl MaybeLeakT1 for NonLeakS {}
|
||||||
|
impl MaybeLeakT2 for NonLeakS {}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod maybe_self_assoc_type {
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
trait TestBase1<T: ?Sized> {}
|
||||||
|
trait TestBase2<T: ?Leak + ?Sized> {}
|
||||||
|
|
||||||
|
trait Test1<T> {
|
||||||
|
type MaybeLeakSelf: TestBase1<Self> where Self: ?Leak;
|
||||||
|
//~^ ERROR the trait bound `Self: Leak` is not satisfied
|
||||||
|
type LeakSelf: TestBase1<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Test2<T> {
|
||||||
|
type MaybeLeakSelf: TestBase2<Self> where Self: ?Leak;
|
||||||
|
type LeakSelf: TestBase2<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Test3 {
|
||||||
|
type Leak1 = LeakS;
|
||||||
|
type Leak2 = NonLeakS;
|
||||||
|
//~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Test4 {
|
||||||
|
type MaybeLeak1: ?Leak = LeakS;
|
||||||
|
type MaybeLeak2: ?Leak = NonLeakS;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Test5: ?Leak {
|
||||||
|
// ok, because assoc types have implicit where Self: Leak
|
||||||
|
type MaybeLeakSelf1: TestBase1<Self>;
|
||||||
|
type MaybeLeakSelf2: TestBase2<Self>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod maybe_self_assoc_const {
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
const fn size_of<T: ?Sized>() -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
const CLeak: usize = size_of::<Self>();
|
||||||
|
const CNonLeak: usize = size_of::<Self>() where Self: ?Leak;
|
||||||
|
//~^ ERROR the trait bound `Self: Leak` is not satisfied
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod methods {
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
fn leak_foo(&self) {}
|
||||||
|
fn maybe_leak_foo(&self) where Self: ?Leak {}
|
||||||
|
fn mut_leak_foo(&mut self) {}
|
||||||
|
// there is no relax bound on corresponding Receiver impl
|
||||||
|
fn mut_maybe_leak_foo(&mut self) where Self: ?Leak {}
|
||||||
|
//~^ `&mut Self` cannot be used as the type of `self` without the `arbitrary_self_types`
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for NonLeakS {}
|
||||||
|
impl Trait for LeakS {}
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
LeakS.leak_foo();
|
||||||
|
LeakS.maybe_leak_foo();
|
||||||
|
NonLeakS.leak_foo();
|
||||||
|
//~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied
|
||||||
|
NonLeakS.maybe_leak_foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,71 @@
|
||||||
|
error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied
|
||||||
|
--> $DIR/maybe-bounds-in-traits.rs:61:22
|
||||||
|
|
|
||||||
|
LL | type Leak2 = NonLeakS;
|
||||||
|
| ^^^^^^^^ the trait `Leak` is not implemented for `NonLeakS`
|
||||||
|
|
|
||||||
|
note: required by a bound in `Test3::Leak2`
|
||||||
|
--> $DIR/maybe-bounds-in-traits.rs:61:9
|
||||||
|
|
|
||||||
|
LL | type Leak2 = NonLeakS;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Test3::Leak2`
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `Self: Leak` is not satisfied
|
||||||
|
--> $DIR/maybe-bounds-in-traits.rs:49:29
|
||||||
|
|
|
||||||
|
LL | type MaybeLeakSelf: TestBase1<Self> where Self: ?Leak;
|
||||||
|
| ^^^^^^^^^^^^^^^ the trait `Leak` is not implemented for `Self`
|
||||||
|
|
|
||||||
|
note: required by a bound in `TestBase1`
|
||||||
|
--> $DIR/maybe-bounds-in-traits.rs:45:21
|
||||||
|
|
|
||||||
|
LL | trait TestBase1<T: ?Sized> {}
|
||||||
|
| ^ required by this bound in `TestBase1`
|
||||||
|
help: consider further restricting `Self`
|
||||||
|
|
|
||||||
|
LL | trait Test1<T>: Leak {
|
||||||
|
| ++++++
|
||||||
|
|
||||||
|
error[E0658]: `&mut Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature
|
||||||
|
--> $DIR/maybe-bounds-in-traits.rs:99:31
|
||||||
|
|
|
||||||
|
LL | fn mut_maybe_leak_foo(&mut self) where Self: ?Leak {}
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
|
||||||
|
= help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
= help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `Self: Leak` is not satisfied
|
||||||
|
--> $DIR/maybe-bounds-in-traits.rs:86:43
|
||||||
|
|
|
||||||
|
LL | const CNonLeak: usize = size_of::<Self>() where Self: ?Leak;
|
||||||
|
| ^^^^ the trait `Leak` is not implemented for `Self`
|
||||||
|
|
|
||||||
|
note: required by a bound in `size_of`
|
||||||
|
--> $DIR/maybe-bounds-in-traits.rs:80:22
|
||||||
|
|
|
||||||
|
LL | const fn size_of<T: ?Sized>() -> usize {
|
||||||
|
| ^ required by this bound in `size_of`
|
||||||
|
help: consider further restricting `Self`
|
||||||
|
|
|
||||||
|
LL | trait Trait: Leak {
|
||||||
|
| ++++++
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied
|
||||||
|
--> $DIR/maybe-bounds-in-traits.rs:109:18
|
||||||
|
|
|
||||||
|
LL | NonLeakS.leak_foo();
|
||||||
|
| ^^^^^^^^ the trait `Leak` is not implemented for `NonLeakS`
|
||||||
|
|
|
||||||
|
note: required by a bound in `methods::Trait::leak_foo`
|
||||||
|
--> $DIR/maybe-bounds-in-traits.rs:95:9
|
||||||
|
|
|
||||||
|
LL | fn leak_foo(&self) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::leak_foo`
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0277, E0658.
|
||||||
|
For more information about an error, try `rustc --explain E0277`.
|
Loading…
Add table
Add a link
Reference in a new issue