Skip to content

Commit f6d1bc6

Browse files
committed
Support ?Trait bounds in supertraits and dyn Trait under a feature gate
1 parent 2ccafed commit f6d1bc6

File tree

34 files changed

+305
-85
lines changed

34 files changed

+305
-85
lines changed

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,8 +1525,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
15251525
continue;
15261526
}
15271527
let is_param = *is_param.get_or_insert_with(compute_is_param);
1528-
if !is_param {
1529-
self.dcx().emit_err(MisplacedRelaxTraitBound { span: bound.span() });
1528+
if !is_param && !self.tcx.features().more_maybe_bounds {
1529+
self.tcx
1530+
.sess
1531+
.create_feature_err(
1532+
MisplacedRelaxTraitBound { span: bound.span() },
1533+
sym::more_maybe_bounds,
1534+
)
1535+
.emit();
15301536
}
15311537
}
15321538
}

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
12161216
itctx,
12171217
TraitBoundModifiers::NONE,
12181218
);
1219+
let bound = (bound, hir::TraitBoundModifier::None);
12191220
let bounds = this.arena.alloc_from_iter([bound]);
12201221
let lifetime_bound = this.elided_dyn_bound(t.span);
12211222
(bounds, lifetime_bound)
@@ -1348,21 +1349,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13481349
// We can safely ignore constness here since AST validation
13491350
// takes care of rejecting invalid modifier combinations and
13501351
// const trait bounds in trait object types.
1351-
GenericBound::Trait(ty, modifiers) => match modifiers.polarity {
1352-
BoundPolarity::Positive | BoundPolarity::Negative(_) => {
1353-
Some(this.lower_poly_trait_ref(
1354-
ty,
1355-
itctx,
1356-
// Still, don't pass along the constness here; we don't want to
1357-
// synthesize any host effect args, it'd only cause problems.
1358-
TraitBoundModifiers {
1359-
constness: BoundConstness::Never,
1360-
..*modifiers
1361-
},
1362-
))
1363-
}
1364-
BoundPolarity::Maybe(_) => None,
1365-
},
1352+
GenericBound::Trait(ty, modifiers) => {
1353+
// Still, don't pass along the constness here; we don't want to
1354+
// synthesize any host effect args, it'd only cause problems.
1355+
let modifiers = TraitBoundModifiers {
1356+
constness: BoundConstness::Never,
1357+
..*modifiers
1358+
};
1359+
let trait_ref = this.lower_poly_trait_ref(ty, itctx, modifiers);
1360+
let polarity = this.lower_trait_bound_modifiers(modifiers);
1361+
Some((trait_ref, polarity))
1362+
}
13661363
GenericBound::Outlives(lifetime) => {
13671364
if lifetime_bound.is_none() {
13681365
lifetime_bound = Some(this.lower_lifetime(lifetime));
@@ -2688,6 +2685,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
26882685
trait_ref: hir::TraitRef { path, hir_ref_id: hir_id },
26892686
span: self.lower_span(span),
26902687
};
2688+
let principal = (principal, hir::TraitBoundModifier::None);
26912689

26922690
// The original ID is taken by the `PolyTraitRef`,
26932691
// so the `Ty` itself needs a different one.

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,14 +1345,28 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13451345
match bound {
13461346
GenericBound::Trait(trait_ref, modifiers) => {
13471347
match (ctxt, modifiers.constness, modifiers.polarity) {
1348-
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
1349-
self.dcx().emit_err(errors::OptionalTraitSupertrait {
1350-
span: trait_ref.span,
1351-
path_str: pprust::path_to_string(&trait_ref.trait_ref.path),
1352-
});
1348+
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_))
1349+
if !self.features.more_maybe_bounds =>
1350+
{
1351+
self.session
1352+
.create_feature_err(
1353+
errors::OptionalTraitSupertrait {
1354+
span: trait_ref.span,
1355+
path_str: pprust::path_to_string(&trait_ref.trait_ref.path),
1356+
},
1357+
sym::more_maybe_bounds,
1358+
)
1359+
.emit();
13531360
}
1354-
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
1355-
self.dcx().emit_err(errors::OptionalTraitObject { span: trait_ref.span });
1361+
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_))
1362+
if !self.features.more_maybe_bounds =>
1363+
{
1364+
self.session
1365+
.create_feature_err(
1366+
errors::OptionalTraitObject { span: trait_ref.span },
1367+
sym::more_maybe_bounds,
1368+
)
1369+
.emit();
13561370
}
13571371
(
13581372
BoundKind::TraitObject,

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ declare_features! (
205205
(unstable, lifetime_capture_rules_2024, "1.76.0", None),
206206
/// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406
207207
(unstable, link_cfg, "1.14.0", None),
208+
/// Allows using `?Trait` trait bounds in more contexts.
209+
(internal, more_maybe_bounds, "CURRENT_RUSTC_VERSION", None),
208210
/// Allows the `multiple_supertrait_upcastable` lint.
209211
(unstable, multiple_supertrait_upcastable, "1.69.0", None),
210212
/// Allow negative trait bounds. This is an internal-only feature for testing the trait solver!

compiler/rustc_hir/src/hir.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2826,7 +2826,11 @@ pub enum TyKind<'hir> {
28262826
OpaqueDef(ItemId, &'hir [GenericArg<'hir>], bool),
28272827
/// A trait object type `Bound1 + Bound2 + Bound3`
28282828
/// where `Bound` is a trait or a lifetime.
2829-
TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
2829+
TraitObject(
2830+
&'hir [(PolyTraitRef<'hir>, TraitBoundModifier)],
2831+
&'hir Lifetime,
2832+
TraitObjectSyntax,
2833+
),
28302834
/// Unused for now.
28312835
Typeof(&'hir AnonConst),
28322836
/// `TyKind::Infer` means the type should be inferred instead of it having been

compiler/rustc_hir/src/intravisit.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
902902
try_visit!(visitor.visit_array_length(length));
903903
}
904904
TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
905-
walk_list!(visitor, visit_poly_trait_ref, bounds);
905+
for (bound, _modifier) in bounds {
906+
try_visit!(visitor.visit_poly_trait_ref(bound));
907+
}
906908
try_visit!(visitor.visit_lifetime(lifetime));
907909
}
908910
TyKind::Typeof(ref expression) => try_visit!(visitor.visit_anon_const(expression)),

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -831,7 +831,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GATArgsCollector<'tcx> {
831831

832832
fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
833833
match ty.kind {
834-
hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments {
834+
hir::TyKind::TraitObject([(trait_ref, _)], ..) => match trait_ref.trait_ref.path.segments {
835835
[s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()),
836836
_ => false,
837837
},

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
652652
debug!(?bounds, ?lifetime, "TraitObject");
653653
let scope = Scope::TraitRefBoundary { s: self.scope };
654654
self.with(scope, |this| {
655-
for bound in bounds {
655+
for (bound, _) in bounds {
656656
this.visit_poly_trait_ref_inner(
657657
bound,
658658
NonLifetimeBinderAllowed::Deny("trait object types"),

compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_middle::bug;
99
use rustc_middle::ty::print::PrintTraitRefExt as _;
1010
use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt};
1111
use rustc_span::symbol::Ident;
12-
use rustc_span::{ErrorGuaranteed, Span, Symbol};
12+
use rustc_span::{sym, ErrorGuaranteed, Span, Symbol};
1313
use rustc_trait_selection::traits;
1414
use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
1515
use smallvec::SmallVec;
@@ -75,10 +75,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
7575
}
7676
}
7777

78-
if unbounds.len() > 1 {
79-
self.dcx().emit_err(errors::MultipleRelaxedDefaultBounds {
80-
spans: unbounds.iter().map(|ptr| ptr.span).collect(),
81-
});
78+
if unbounds.len() > 1 && !tcx.features().more_maybe_bounds {
79+
self.tcx()
80+
.sess
81+
.create_feature_err(
82+
errors::MultipleRelaxedDefaultBounds {
83+
spans: unbounds.iter().map(|ptr| ptr.span).collect(),
84+
},
85+
sym::more_maybe_bounds,
86+
)
87+
.emit();
8288
}
8389

8490
let mut seen_sized_unbound = false;

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
698698
&self,
699699
associated_types: FxIndexMap<Span, FxIndexSet<DefId>>,
700700
potential_assoc_types: Vec<usize>,
701-
trait_bounds: &[hir::PolyTraitRef<'_>],
701+
trait_bounds: &[(hir::PolyTraitRef<'_>, hir::TraitBoundModifier)],
702702
) {
703703
if associated_types.values().all(|v| v.is_empty()) {
704704
return;
@@ -744,12 +744,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
744744
// related to issue #91997, turbofishes added only when in an expr or pat
745745
let mut in_expr_or_pat = false;
746746
if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
747-
let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.trait_ref.hir_ref_id));
747+
let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.0.trait_ref.hir_ref_id));
748748
in_expr_or_pat = match grandparent {
749749
Node::Expr(_) | Node::Pat(_) => true,
750750
_ => false,
751751
};
752-
match bound.trait_ref.path.segments {
752+
match bound.0.trait_ref.path.segments {
753753
// FIXME: `trait_ref.path.span` can point to a full path with multiple
754754
// segments, even though `trait_ref.path.segments` is of length `1`. Work
755755
// around that bug here, even though it should be fixed elsewhere.
@@ -790,7 +790,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
790790
// and we can then use their span to indicate this to the user.
791791
let bound_names = trait_bounds
792792
.iter()
793-
.filter_map(|poly_trait_ref| {
793+
.filter_map(|(poly_trait_ref, _)| {
794794
let path = poly_trait_ref.trait_ref.path.segments.last()?;
795795
let args = path.args?;
796796

0 commit comments

Comments
 (0)