From 5bb36db30ea7bc4bd128bc3a35d896ba6c40aaf4 Mon Sep 17 00:00:00 2001 From: Bryanskiy Date: Fri, 23 Feb 2024 16:39:57 +0300 Subject: [PATCH] initial implementation for default auto traits --- compiler/rustc_hir/src/lang_items.rs | 6 + compiler/rustc_hir_analysis/src/bounds.rs | 26 +- compiler/rustc_hir_analysis/src/check/mod.rs | 5 +- .../src/collect/item_bounds.rs | 8 +- .../src/collect/predicates_of.rs | 54 +++- .../src/hir_ty_lowering/bounds.rs | 243 +++++++++++++++--- .../src/hir_ty_lowering/object_safety.rs | 14 + .../src/multiple_supertrait_upcastable.rs | 3 +- compiler/rustc_middle/src/ty/context.rs | 23 ++ compiler/rustc_middle/src/ty/print/pretty.rs | 65 +++-- .../src/solve/assembly/structural_traits.rs | 2 +- .../src/solve/trait_goals.rs | 42 +-- compiler/rustc_session/src/options.rs | 2 + compiler/rustc_span/src/symbol.rs | 9 + .../src/traits/object_safety.rs | 23 +- .../src/traits/select/candidate_assembly.rs | 39 +-- .../src/traits/select/mod.rs | 2 +- compiler/rustc_type_ir/src/interner.rs | 2 + .../backward-compatible-lazy-bounds-pass.rs | 26 ++ .../default_auto_traits/default-bounds.rs | 44 ++++ .../default_auto_traits/default-bounds.stderr | 31 +++ .../extern-types.current.stderr | 17 ++ .../extern-types.next.stderr | 17 ++ .../default_auto_traits/extern-types.rs | 52 ++++ .../maybe-bounds-in-dyn-traits.rs | 78 ++++++ .../maybe-bounds-in-dyn-traits.stderr | 23 ++ .../maybe-bounds-in-traits.rs | 117 +++++++++ .../maybe-bounds-in-traits.stderr | 71 +++++ 28 files changed, 931 insertions(+), 113 deletions(-) create mode 100644 tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs create mode 100644 tests/ui/traits/default_auto_traits/default-bounds.rs create mode 100644 tests/ui/traits/default_auto_traits/default-bounds.stderr create mode 100644 tests/ui/traits/default_auto_traits/extern-types.current.stderr create mode 100644 tests/ui/traits/default_auto_traits/extern-types.next.stderr create mode 100644 tests/ui/traits/default_auto_traits/extern-types.rs create mode 100644 tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs create mode 100644 tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr create mode 100644 tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs create mode 100644 tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index e7398fd222636..a3fc507246763 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -414,6 +414,12 @@ language_item_table! { EffectsIntersectionOutput, sym::EffectsIntersectionOutput, effects_intersection_output, Target::AssocTy, GenericRequirement::None; EffectsCompat, sym::EffectsCompat, effects_compat, Target::Trait, GenericRequirement::Exact(1); EffectsTyCompat, sym::EffectsTyCompat, effects_ty_compat, Target::Trait, GenericRequirement::Exact(1); + + // 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; } pub enum GenericRequirement { diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index c30a6f1eeb910..62571e1dbf0a9 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -166,11 +166,27 @@ impl<'tcx> Bounds<'tcx> { )); } - pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) { - let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span)); - let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]); - // Preferable to put this obligation first, since we report better errors for sized ambiguity. - self.clauses.insert(0, (trait_ref.upcast(tcx), span)); + pub fn push_lang_item_trait( + &mut self, + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + lang_item: LangItem, + span: Span, + ) { + assert_eq!(lang_item.target(), rustc_hir::Target::Trait); + if lang_item == LangItem::Sized { + let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span)); + let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]); + // Preferable to put this obligation first, since we report better errors for sized ambiguity. + self.clauses.insert(0, (trait_ref.upcast(tcx), span)); + } else { + // Do not generate default bounds if lang item was not defined + let Some(trait_def_id) = tcx.lang_items().get(lang_item) else { + return; + }; + let trait_ref = ty::TraitRef::new(tcx, trait_def_id, [ty]); + self.clauses.push((trait_ref.upcast(tcx), span)); + } } pub fn clauses( diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 678b8c89a5054..a02438aa72a21 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -349,9 +349,8 @@ fn bounds_from_generic_predicates<'tcx>( ty::ClauseKind::Trait(trait_predicate) => { let entry = types.entry(trait_predicate.self_ty()).or_default(); let def_id = trait_predicate.def_id(); - if Some(def_id) != tcx.lang_items().sized_trait() { - // Type params are `Sized` by default, do not add that restriction to the list - // if it is a positive requirement. + if !tcx.is_default_trait(def_id) { + // Do not add that restriction to the list if it is a positive requirement. entry.push(trait_predicate.def_id()); } } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index ec48c781c0e43..233299d20613b 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -34,8 +34,8 @@ fn associated_type_bounds<'tcx>( let icx = ItemCtxt::new(tcx, assoc_item_def_id); let mut bounds = icx.lowerer().lower_mono_bounds(item_ty, hir_bounds, filter); - // Associated types are implicitly sized unless a `?Sized` bound is found - icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); + // Implicit bounds are added to associated types unless a `?Trait` bound is found + icx.lowerer().add_implicit_traits(&mut bounds, item_ty, hir_bounds, None, span); let trait_def_id = tcx.local_parent(assoc_item_def_id); let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); @@ -74,8 +74,8 @@ fn opaque_type_bounds<'tcx>( ty::print::with_reduced_queries!({ let icx = ItemCtxt::new(tcx, opaque_def_id); let mut bounds = icx.lowerer().lower_mono_bounds(item_ty, hir_bounds, filter); - // Opaque types are implicitly sized unless a `?Sized` bound is found - icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); + // Implicit bounds are added to opaque types unless a `?Trait` bound is found + icx.lowerer().add_implicit_traits(&mut bounds, item_ty, hir_bounds, None, span); debug!(?bounds); tcx.arena.alloc_from_iter(bounds.clauses(tcx)) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 6ac4802b19514..7a12de0c6408f 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -144,7 +144,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } ItemKind::Trait(_, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, self_bounds) => { - is_trait = Some(self_bounds); + is_trait = Some((self_bounds, item.span)); } ItemKind::Fn(sig, _, _) => { @@ -159,6 +159,34 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen _ => {} } }; + 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: Trait` clauses on trait associated items. + // See comment on `add_implicit_super_traits` for more details. + if !icx.lowerer().requires_implicit_supertraits(parent, trait_bounds, trait_generics) { + let mut bounds = Bounds::default(); + let self_ty_where_predicates = (parent, item.generics.predicates); + icx.lowerer().add_implicit_traits_with_filter( + &mut bounds, + tcx.types.self_param, + &[], + Some(self_ty_where_predicates), + item.span, + |tr| tr != hir::LangItem::Sized, + ); + predicates.extend(bounds.clauses(tcx)); + } + } let generics = tcx.generics_of(def_id); @@ -167,11 +195,18 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // on a trait we must also consider the bounds that follow the trait's name, // like `trait Foo: A + B + C`. if let Some(self_bounds) = is_trait { - let bounds = icx.lowerer().lower_mono_bounds( + let mut bounds = icx.lowerer().lower_mono_bounds( tcx.types.self_param, - self_bounds, + self_bounds.0, PredicateFilter::All, ); + icx.lowerer().add_implicit_super_traits( + def_id, + &mut bounds, + self_bounds.0, + hir_generics, + self_bounds.1, + ); predicates.extend(bounds.clauses(tcx)); effects_min_tys.extend(bounds.effects_min_tys()); } @@ -197,8 +232,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen GenericParamKind::Type { .. } => { let param_ty = icx.lowerer().lower_ty_param(param.hir_id); let mut bounds = Bounds::default(); - // Params are implicitly sized unless a `?Sized` bound is found - icx.lowerer().add_sized_bound( + // Implicit bounds are added to type params unless a `?Trait` bound is found + icx.lowerer().add_implicit_traits( &mut bounds, param_ty, &[], @@ -620,7 +655,14 @@ pub(super) fn implied_predicates_with_filter( let icx = ItemCtxt::new(tcx, trait_def_id); let self_param_ty = tcx.types.self_param; - let superbounds = icx.lowerer().lower_mono_bounds(self_param_ty, bounds, filter); + let mut superbounds = icx.lowerer().lower_mono_bounds(self_param_ty, bounds, filter); + icx.lowerer().add_implicit_super_traits( + trait_def_id, + &mut superbounds, + bounds, + generics, + item.span, + ); let where_bounds_that_match = icx.probe_ty_param_bounds_in_generics( generics, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 7f4c75d3a6a21..b8583e4bbc6e3 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -20,26 +20,192 @@ use crate::hir_ty_lowering::{ AssocItemQSelf, HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason, }; -impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { - /// Add a `Sized` bound to the `bounds` if appropriate. +impl<'tcx, 'a> dyn HirTyLowerer<'tcx> + '_ +where + 'tcx: 'a, +{ + /// 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 `Sized`, `?Sized` or `!Sized`. - pub(crate) fn add_sized_bound( + /// Doesn't add the bound if the HIR bounds contain any of `Trait`, `?Trait` or `!Trait`. + pub(crate) fn add_implicit_traits( &self, bounds: &mut Bounds<'tcx>, self_ty: Ty<'tcx>, - hir_bounds: &'tcx [hir::GenericBound<'tcx>], + hir_bounds: &'a [hir::GenericBound<'a>], + self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + span: Span, + ) { + self.add_implicit_traits_with_filter( + bounds, + self_ty, + hir_bounds, + self_ty_where_predicates, + span, + |_| true, + ); + } + + pub(crate) fn requires_implicit_supertraits( + &self, + trait_def_id: LocalDefId, + hir_bounds: &'a [hir::GenericBound<'a>], + hir_generics: &'tcx hir::Generics<'tcx>, + ) -> bool { + // FIXME(experimental_default_bounds): Default bounds on `Pointee::Metadata` + // causes a normalization fail. + if Some(trait_def_id.to_def_id()) == self.tcx().lang_items().pointee_trait() { + return true; + } + + 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>) -> 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. + /// 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 {} + /// 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 : Trait {} + /// //~^ 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 `TypeBinding` was found in a trait header. + pub(crate) fn add_implicit_super_traits( + &self, + trait_def_id: LocalDefId, + bounds: &mut Bounds<'tcx>, + hir_bounds: &'a [hir::GenericBound<'a>], + hir_generics: &'tcx hir::Generics<'tcx>, + span: Span, + ) { + assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias)); + if self.requires_implicit_supertraits(trait_def_id, hir_bounds, hir_generics) { + let self_ty_where_predicates = (trait_def_id, hir_generics.predicates); + self.add_implicit_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_implicit_traits_with_filter( + &self, + bounds: &mut Bounds<'tcx>, + self_ty: Ty<'tcx>, + hir_bounds: &'a [hir::GenericBound<'a>], + 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_implicit_trait( + *default_trait, + bounds, + self_ty, + hir_bounds, + self_ty_where_predicates, + span, + ); + }, + ); + } + + pub(crate) fn add_implicit_trait( + &self, + trait_: hir::LangItem, + bounds: &mut Bounds<'tcx>, + self_ty: Ty<'tcx>, + hir_bounds: &'a [hir::GenericBound<'a>], self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, span: Span, ) { let tcx = self.tcx(); - let sized_def_id = tcx.lang_items().sized_trait(); - let mut seen_negative_sized_bound = false; - let mut seen_positive_sized_bound = false; + let trait_id = tcx.lang_items().get(trait_); + + if self.check_for_implicit_trait(trait_id, hir_bounds, self_ty_where_predicates) { + // There was no `?Trait` or `!Trait` bound; + // add `Trait` if it's available. + bounds.push_lang_item_trait(tcx, self_ty, trait_, span); + } + } + + fn check_for_implicit_trait( + &self, + trait_def_id: Option, + hir_bounds: &'a [hir::GenericBound<'a>], + self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + ) -> bool { + let Some(trait_def_id) = trait_def_id else { + return false; + }; + let tcx = self.tcx(); + let mut seen_negative_bound = false; + let mut seen_positive_bound = false; // Try to find an unbound in bounds. 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<'a>]| { for hir_bound in hir_bounds { let hir::GenericBound::Trait(ptr, modifier) = hir_bound else { continue; @@ -47,17 +213,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match modifier { hir::TraitBoundModifier::Maybe => unbounds.push(ptr), hir::TraitBoundModifier::Negative => { - if let Some(sized_def_id) = sized_def_id - && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) - { - seen_negative_sized_bound = true; + if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) { + seen_negative_bound = true; } } hir::TraitBoundModifier::None => { - if let Some(sized_def_id) = sized_def_id - && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) - { - seen_positive_sized_bound = true; + if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) { + seen_positive_bound = true; } } _ => {} @@ -93,30 +255,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; } - let mut seen_sized_unbound = false; + let mut seen_unbound = false; for unbound in unbounds { - if let Some(sized_def_id) = sized_def_id - && unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) - { - seen_sized_unbound = true; - continue; + let unbound_def_id = unbound.trait_ref.trait_def_id(); + if unbound_def_id == Some(trait_def_id) { + seen_unbound = true; } - // There was a `?Trait` bound, but it was not `?Sized`; warn. - self.dcx().span_warn( - unbound.span, - "relaxing a default bound only does something for `?Sized`; \ - all other traits are not bound by default", - ); - } - if seen_sized_unbound || seen_negative_sized_bound || seen_positive_sized_bound { - // There was in fact a `?Sized`, `!Sized` or explicit `Sized` bound; - // we don't need to do anything. - } else if sized_def_id.is_some() { - // There was no `?Sized`, `!Sized` or explicit `Sized` bound; - // add `Sized` if it's available. - bounds.push_sized(tcx, self_ty, span); + let emit_relax_warn = || { + let unbound_traits = + match self.tcx().sess.opts.unstable_opts.experimental_default_bounds { + true => "`?Sized` and `experimental_default_bounds`", + false => "`?Sized`", + }; + tcx.dcx().span_warn( + unbound.span, + format!( + "relaxing a default bound only does something for {}; \ + 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_warn(), + None => emit_relax_warn(), + _ => {} + } } + + !(seen_unbound || seen_negative_bound || seen_positive_bound) } /// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any. diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index 31d1750f33dfd..aff25ad53b705 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -61,6 +61,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + let ast_bounds: Vec<_> = hir_trait_bounds + .iter() + .map(|&(trait_ref, polarity)| hir::GenericBound::Trait(trait_ref, polarity)) + .collect(); + + self.add_implicit_traits_with_filter( + &mut bounds, + dummy_self, + &ast_bounds, + None, + span, + |tr| tr != hir::LangItem::Sized, + ); + let mut trait_bounds = vec![]; let mut projection_bounds = vec![]; for (pred, span) in bounds.clauses(tcx) { diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index 978109aba5f92..a7aefab8711b8 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -47,7 +47,8 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { .explicit_super_predicates_of(def_id) .predicates .into_iter() - .filter_map(|(pred, _)| pred.as_trait_clause()); + .filter_map(|(pred, _)| pred.as_trait_clause()) + .filter(|pred| !cx.tcx.is_default_trait(pred.def_id())); if direct_super_traits_iter.count() > 1 { cx.emit_span_lint( MULTIPLE_SUPERTRAIT_UPCASTABLE, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9b39b84970420..98325a7a47d6b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -373,6 +373,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { 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 { lang_item_to_trait_lang_item(self.lang_items().from_def_id(def_id)?) } @@ -1545,6 +1549,25 @@ impl<'tcx> TyCtxt<'tcx> { self.type_of(ordering_enum).no_bound_vars().unwrap() } + 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)) + } + /// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to /// compare against another `DefId`, since `is_diagnostic_item` is cheaper. pub fn get_diagnostic_item(self, name: Symbol) -> Option { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 319fb7ef03bb3..955f7e84c7220 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -985,25 +985,32 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let mut traits = FxIndexMap::default(); let mut fn_traits = FxIndexMap::default(); - let mut has_sized_bound = false; - let mut has_negative_sized_bound = false; + let mut default_trait_bounds = FxHashSet::default(); + let mut default_negative_trait_bounds = FxHashSet::default(); let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new(); - for (predicate, _) in bounds.iter_instantiated_copied(tcx, args) { + 'pred: for (predicate, _) in bounds.iter_instantiated_copied(tcx, args) { let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { ty::ClauseKind::Trait(pred) => { let trait_ref = bound_predicate.rebind(pred.trait_ref); - // Don't print `+ Sized`, but rather `+ ?Sized` if absent. - if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) { - match pred.polarity { - ty::PredicatePolarity::Positive => { - has_sized_bound = true; - continue; + // Don't print implicit bounds. + for default_trait in tcx.default_traits() { + let lang_item_id = tcx.lang_items().get(*default_trait); + if let Some(default_trait_id) = lang_item_id + && trait_ref.def_id() == default_trait_id + { + match pred.polarity { + ty::PredicatePolarity::Positive => { + default_trait_bounds.insert(*default_trait); + continue 'pred; + } + ty::PredicatePolarity::Negative => { + default_negative_trait_bounds.insert(*default_trait); + } } - ty::PredicatePolarity::Negative => has_negative_sized_bound = true, } } @@ -1041,7 +1048,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let mut first = true; // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait - let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !has_sized_bound; + let paren_needed = + fn_traits.len() > 1 || traits.len() > 0 || default_trait_bounds.is_empty(); for (fn_once_trait_ref, entry) in fn_traits { write!(self, "{}", if first { "" } else { " + " })?; @@ -1189,16 +1197,30 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { })?; } - let add_sized = has_sized_bound && (first || has_negative_sized_bound); - let add_maybe_sized = !has_sized_bound && !has_negative_sized_bound; - if add_sized || add_maybe_sized { - if !first { - write!(self, " + ")?; + for default_trait in tcx.default_traits() { + if tcx.lang_items().get(*default_trait).is_none() { + // default bounds weren't generated + continue; } - if add_maybe_sized { - write!(self, "?")?; + + let has_default_bound = default_trait_bounds.contains(default_trait); + let has_negative_default_bound = default_negative_trait_bounds.contains(default_trait); + + let add_bound = has_default_bound && (first || has_negative_default_bound); + let add_maybe_bound = !has_default_bound && !has_negative_default_bound; + + if add_bound || add_maybe_bound { + if !first { + write!(self, " + ")?; + } else { + first = false; + } + + if add_maybe_bound { + write!(self, "?")?; + } + write!(self, "{}", default_trait.variant_name())?; } - write!(self, "Sized")?; } if !with_forced_trimmed_paths() { @@ -1417,6 +1439,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { auto_traits.sort_by_cached_key(|did| with_no_trimmed_paths!(self.tcx().def_path_str(*did))); for def_id in auto_traits { + if self.tcx().is_default_trait(def_id) + && self.tcx().lang_items().sized_trait() != Some(def_id) + { + continue; + } if !first { p!(" + "); } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index a57338acaab29..4b55fc5293c16 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -32,6 +32,7 @@ where | ty::Float(_) | ty::FnDef(..) | ty::FnPtr(..) + | ty::Foreign(..) | ty::Error(_) | ty::Never | ty::Char => Ok(vec![]), @@ -41,7 +42,6 @@ where ty::Dynamic(..) | ty::Param(..) - | ty::Foreign(..) | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) | ty::Placeholder(..) | ty::Bound(..) diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 1314b7eb6ffc6..cf5256b674d57 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1083,6 +1083,25 @@ where goal: Goal>, ) -> Option, NoSolution>> { 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() { // Stall int and float vars until they are resolved to a concrete // numerical type. That's because the check for impls below treats @@ -1093,6 +1112,10 @@ where 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 // types, and therefore have no built-in auto impl. ty::Dynamic(..) @@ -1152,24 +1175,7 @@ where | ty::CoroutineWitness(..) | ty::Never | ty::Tuple(_) - | ty::Adt(_, _) => { - 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::Adt(_, _) => check_impls(), ty::Error(_) => None, } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index df72e2430fd50..17d5b3b601ab9 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1707,6 +1707,8 @@ options! { "emit the bc module with thin LTO info (default: yes)"), enforce_type_length_limit: bool = (false, parse_bool, [TRACKED], "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 symbols from executables, as if they were dynamic libraries"), external_clangrt: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a2e94492f8c23..f3f324fbe7349 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -707,6 +707,15 @@ symbols! { default_fn, default_lib_allocator, 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_params, delayed_bug_from_inside_query, diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 8e1fc0d7fe687..bfc22355d5d57 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -14,6 +14,7 @@ use std::ops::ControlFlow; use rustc_errors::FatalError; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::LangItem; use rustc_middle::query::Providers; use rustc_middle::ty::{ self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt, @@ -711,8 +712,26 @@ fn receiver_is_dispatchable<'tcx>( ty::TraitRef::new_from_args(tcx, trait_def_id, args).upcast(tcx) }; - let caller_bounds = - param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]); + // U: `experimental_default_bounds` + let default_auto_trait_predicates = { + let mut predicates = vec![]; + for default_trait in tcx.default_traits().iter() { + if *default_trait != LangItem::Sized + && let Some(trait_def_id) = tcx.lang_items().get(*default_trait) + { + let predicate = + ty::TraitRef::new(tcx, trait_def_id, [unsized_self_ty]).upcast(tcx); + predicates.push(predicate); + } + } + predicates + }; + + let caller_bounds = param_env + .caller_bounds() + .iter() + .chain([unsize_predicate, trait_predicate]) + .chain(default_auto_trait_predicates); ty::ParamEnv::new(tcx.mk_clauses_from_iter(caller_bounds), param_env.reveal()) }; diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index cb8deeaedb66f..7fc77fd3f2cdd 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -722,6 +722,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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) { match *self_ty.kind() { ty::Dynamic(..) => { @@ -735,6 +751,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // we don't add any `..` impl. Default traits could // still be provided by a manual implementation for // 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::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) @@ -825,22 +847,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Coroutine(..) | ty::Never | ty::Tuple(_) - | ty::CoroutineWitness(..) => { - // 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) - } - } + | ty::CoroutineWitness(..) => check_impls(), ty::Error(_) => {} // do not add an auto trait impl for `ty::Error` for now. } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index f002fa27db27f..1d84298f9ed05 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2336,6 +2336,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::Error(_) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Never + | ty::Foreign(..) | ty::Char => ty::Binder::dummy(Vec::new()), // Treat this like `struct str([u8]);` @@ -2344,7 +2345,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ty::Placeholder(..) | ty::Dynamic(..) | ty::Param(..) - | ty::Foreign(..) | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) | ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index f2492ede4f5ea..312b9f451aa68 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -230,6 +230,8 @@ pub trait Interner: 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; fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator; diff --git a/tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs b/tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs new file mode 100644 index 0000000000000..5a8f6cdeba45a --- /dev/null +++ b/tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs @@ -0,0 +1,26 @@ +//@ check-pass +//@ compile-flags: -Zexperimental-default-bounds + +#![feature(auto_traits, lang_items, no_core, start, 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 {} +trait Trait1 : Trait {} + +trait Trait2 { + type Type; +} +trait Trait3 = Trait2; + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { 0 } diff --git a/tests/ui/traits/default_auto_traits/default-bounds.rs b/tests/ui/traits/default_auto_traits/default-bounds.rs new file mode 100644 index 0000000000000..21dddca7c69d7 --- /dev/null +++ b/tests/ui/traits/default_auto_traits/default-bounds.rs @@ -0,0 +1,44 @@ +//@ compile-flags: -Zexperimental-default-bounds + +#![feature( + auto_traits, + lang_items, + negative_impls, + no_core, + start, + 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) {} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + // 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); + 0 +} diff --git a/tests/ui/traits/default_auto_traits/default-bounds.stderr b/tests/ui/traits/default_auto_traits/default-bounds.stderr new file mode 100644 index 0000000000000..64a35ac69c89c --- /dev/null +++ b/tests/ui/traits/default_auto_traits/default-bounds.stderr @@ -0,0 +1,31 @@ +error[E0277]: the trait bound `Forbidden: SyncDrop` is not satisfied + --> $DIR/default-bounds.rs:39: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:34:8 + | +LL | fn bar(_: T) {} + | ^ required by this bound in `bar` + +error[E0277]: the trait bound `Forbidden: Leak` is not satisfied + --> $DIR/default-bounds.rs:39: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:34:11 + | +LL | fn bar(_: T) {} + | ^^^^ required by this bound in `bar` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/default_auto_traits/extern-types.current.stderr b/tests/ui/traits/default_auto_traits/extern-types.current.stderr new file mode 100644 index 0000000000000..e1bd99b900f56 --- /dev/null +++ b/tests/ui/traits/default_auto_traits/extern-types.current.stderr @@ -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) {} + | ^ required by this bound in `foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/default_auto_traits/extern-types.next.stderr b/tests/ui/traits/default_auto_traits/extern-types.next.stderr new file mode 100644 index 0000000000000..e1bd99b900f56 --- /dev/null +++ b/tests/ui/traits/default_auto_traits/extern-types.next.stderr @@ -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) {} + | ^ required by this bound in `foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/default_auto_traits/extern-types.rs b/tests/ui/traits/default_auto_traits/extern-types.rs new file mode 100644 index 0000000000000..06f79af2b5634 --- /dev/null +++ b/tests/ui/traits/default_auto_traits/extern-types.rs @@ -0,0 +1,52 @@ +//@ compile-flags: -Zexperimental-default-bounds +//@ revisions: current next +//@ [next] compile-flags: -Znext-solver + +#![feature(auto_traits, extern_types, lang_items, negative_impls, no_core, start, 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) {} + +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 + } +} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs new file mode 100644 index 0000000000000..9d28df8d53a83 --- /dev/null +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs @@ -0,0 +1,78 @@ +//@ compile-flags: -Zexperimental-default-bounds + +#![feature( + auto_traits, + lang_items, + more_maybe_bounds, + negative_impls, + no_core, start, + trait_upcasting, + rustc_attrs +)] +#![allow(internal_features)] +#![no_std] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +pub unsafe trait Copy {} +unsafe impl<'a, T: ?Sized> Copy for &'a T {} + +#[lang = "receiver"] +trait Receiver {} +impl Receiver for &T {} + +#[lang = "unsize"] +trait Unsize {} + +#[lang = "coerce_unsized"] +trait CoerceUnsized {} +impl<'a, 'b: 'a, T: ?Sized + ?Leak + Unsize, U: ?Sized + ?Leak> CoerceUnsized<&'a U> for &'b T {} + +#[lang = "dispatch_from_dyn"] +trait DispatchFromDyn {} +impl<'a, T: ?Sized + ?Leak + Unsize, U: ?Sized + ?Leak> DispatchFromDyn<&'a U> for &'a T {} + +#[lang = "default_trait1"] +auto trait Leak {} + +#[lang = "default_trait2"] +auto trait SyncDrop {} + +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 {} + +// add implicit supertraits +trait Trait2 {} +impl Trait2 for LeakS {} + +fn test_trait_object() { + 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(); +} + +fn test_traits_upcasting() { + let _: &dyn Trait2<()> = &LeakS; + let _: &dyn Leak = &LeakS; + let _: &dyn SyncDrop = &LeakS; +} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { 0 } diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr new file mode 100644 index 0000000000000..6c31299d80fd7 --- /dev/null +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied + --> $DIR/maybe-bounds-in-dyn-traits.rs:61:25 + | +LL | let _: &dyn Trait = &NonLeakS; + | ^^^^^^^^^ the trait `Leak` is not implemented for `NonLeakS` + | + = note: required for the cast from `&NonLeakS` to `&dyn Trait` + +error[E0277]: the trait bound `dyn Trait: Leak` is not satisfied + --> $DIR/maybe-bounds-in-dyn-traits.rs:66: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:49: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`. diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs new file mode 100644 index 0000000000000..0951060ce27ef --- /dev/null +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs @@ -0,0 +1,117 @@ +//@ compile-flags: -Zexperimental-default-bounds + +#![feature( + auto_traits, + associated_type_defaults, + generic_const_items, + lang_items, + more_maybe_bounds, + negative_impls, + no_core, + start, + rustc_attrs +)] +#![allow(incomplete_features)] +#![no_std] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[lang = "receiver"] +trait Receiver {} +impl Receiver for &T {} +impl Receiver 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 {} + trait TestBase2 {} + + trait Test1 { + type MaybeLeakSelf: TestBase1 where Self: ?Leak; + //~^ ERROR the trait bound `Self: Leak` is not satisfied + type LeakSelf: TestBase1; + } + + trait Test2 { + type MaybeLeakSelf: TestBase2 where Self: ?Leak; + type LeakSelf: TestBase2; + } + + 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 has implicit where Self: Leak + type MaybeLeakSelf1: TestBase1; + type MaybeLeakSelf2: TestBase2; + } +} + +mod maybe_self_assoc_const { + use crate::*; + + const fn size_of() -> usize { + 0 + } + + trait Trait { + const CLeak: usize = size_of::(); + const CNonLeak: usize = size_of::() 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(); + } +} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { 0 } diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr new file mode 100644 index 0000000000000..f66450203a3d8 --- /dev/null +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr @@ -0,0 +1,71 @@ +error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied + --> $DIR/maybe-bounds-in-traits.rs:62: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:62: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:50:29 + | +LL | type MaybeLeakSelf: TestBase1 where Self: ?Leak; + | ^^^^^^^^^^^^^^^ the trait `Leak` is not implemented for `Self` + | +note: required by a bound in `TestBase1` + --> $DIR/maybe-bounds-in-traits.rs:46:21 + | +LL | trait TestBase1 {} + | ^ required by this bound in `TestBase1` +help: consider further restricting `Self` + | +LL | trait Test1: 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:100:31 + | +LL | fn mut_maybe_leak_foo(&mut self) where Self: ?Leak {} + | ^^^^^^^^^ + | + = note: see issue #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`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0277]: the trait bound `Self: Leak` is not satisfied + --> $DIR/maybe-bounds-in-traits.rs:87:43 + | +LL | const CNonLeak: usize = size_of::() 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:81:22 + | +LL | const fn size_of() -> 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:110: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:96: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`.