Skip to content

Commit

Permalink
Represent TraitBoundModifiers as distinct parts in HIR
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Oct 22, 2024
1 parent 86d69c7 commit febb3f7
Show file tree
Hide file tree
Showing 18 changed files with 116 additions and 117 deletions.
4 changes: 2 additions & 2 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2697,7 +2697,7 @@ impl fmt::Debug for ImplPolarity {
}

/// The polarity of a trait bound.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)]
#[derive(HashStable_Generic)]
pub enum BoundPolarity {
/// `Type: Trait`
Expand All @@ -2719,7 +2719,7 @@ impl BoundPolarity {
}

/// The constness of a trait bound.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)]
#[derive(HashStable_Generic)]
pub enum BoundConstness {
/// `Type: Trait`
Expand Down
22 changes: 4 additions & 18 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1956,7 +1956,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {

hir::GenericBound::Trait(hir::PolyTraitRef {
bound_generic_params: &[],
modifiers: hir::TraitBoundModifier::None,
modifiers: hir::TraitBoundModifiers::NONE,
trait_ref: hir::TraitRef {
path: self.make_lang_item_path(trait_lang_item, opaque_ty_span, Some(bound_args)),
hir_ref_id: self.next_id(),
Expand Down Expand Up @@ -2445,22 +2445,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_trait_bound_modifiers(
&mut self,
modifiers: TraitBoundModifiers,
) -> hir::TraitBoundModifier {
// Invalid modifier combinations will cause an error during AST validation.
// Arbitrarily pick a placeholder for them to make compilation proceed.
match (modifiers.constness, modifiers.polarity) {
(BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None,
(_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
(BoundConstness::Never, BoundPolarity::Negative(_)) => {
if self.tcx.features().negative_bounds {
hir::TraitBoundModifier::Negative
} else {
hir::TraitBoundModifier::None
}
}
(BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const,
(BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst,
}
) -> hir::TraitBoundModifiers {
hir::TraitBoundModifiers { constness: modifiers.constness, polarity: modifiers.polarity }
}

// Helper methods for building HIR.
Expand Down Expand Up @@ -2626,7 +2612,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => {
let principal = hir::PolyTraitRef {
bound_generic_params: &[],
modifiers: hir::TraitBoundModifier::None,
modifiers: hir::TraitBoundModifiers::NONE,
trait_ref: hir::TraitRef { path, hir_ref_id: hir_id },
span: self.lower_span(span),
};
Expand Down
29 changes: 13 additions & 16 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use rustc_ast::{
LitKind, TraitObjectSyntax, UintTy,
};
pub use rustc_ast::{
BinOp, BinOpKind, BindingMode, BorrowKind, ByRef, CaptureBy, ImplPolarity, IsAuto, Movability,
Mutability, UnOp,
BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy,
ImplPolarity, IsAuto, Movability, Mutability, UnOp,
};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::sorted_map::SortedMap;
Expand Down Expand Up @@ -502,19 +502,16 @@ pub enum GenericArgsParentheses {
ParenSugar,
}

/// A modifier on a trait bound.
/// The modifiers on a trait bound.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum TraitBoundModifier {
/// `Type: Trait`
None,
/// `Type: !Trait`
Negative,
/// `Type: ?Trait`
Maybe,
/// `Type: const Trait`
Const,
/// `Type: ~const Trait`
MaybeConst,
pub struct TraitBoundModifiers {
pub constness: BoundConstness,
pub polarity: BoundPolarity,
}

impl TraitBoundModifiers {
pub const NONE: Self =
TraitBoundModifiers { constness: BoundConstness::Never, polarity: BoundPolarity::Positive };
}

#[derive(Clone, Copy, Debug, HashStable_Generic)]
Expand Down Expand Up @@ -3180,7 +3177,7 @@ pub struct PolyTraitRef<'hir> {
/// The constness and polarity of the trait ref.
///
/// The `async` modifier is lowered directly into a different trait for now.
pub modifiers: TraitBoundModifier,
pub modifiers: TraitBoundModifiers,

/// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`.
pub trait_ref: TraitRef<'hir>,
Expand Down Expand Up @@ -4085,7 +4082,7 @@ mod size_asserts {
static_assert_size!(ForeignItem<'_>, 88);
static_assert_size!(ForeignItemKind<'_>, 56);
static_assert_size!(GenericArg<'_>, 16);
static_assert_size!(GenericBound<'_>, 48);
static_assert_size!(GenericBound<'_>, 64);
static_assert_size!(Generics<'_>, 56);
static_assert_size!(Impl<'_>, 80);
static_assert_size!(ImplItem<'_>, 88);
Expand Down
35 changes: 17 additions & 18 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let hir::GenericBound::Trait(ptr) = hir_bound else {
continue;
};
match ptr.modifiers {
hir::TraitBoundModifier::Maybe => unbounds.push(ptr),
hir::TraitBoundModifier::Negative => {
match ptr.modifiers.polarity {
hir::BoundPolarity::Maybe(_) => unbounds.push(ptr),
hir::BoundPolarity::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;
}
}
hir::TraitBoundModifier::None => {
hir::BoundPolarity::Positive => {
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;
}
}
_ => {}
}
}
};
Expand Down Expand Up @@ -169,20 +168,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

match hir_bound {
hir::GenericBound::Trait(poly_trait_ref) => {
let (constness, polarity) = match poly_trait_ref.modifiers {
hir::TraitBoundModifier::Const => {
(Some(ty::BoundConstness::Const), ty::PredicatePolarity::Positive)
}
hir::TraitBoundModifier::MaybeConst => (
Some(ty::BoundConstness::ConstIfConst),
ty::PredicatePolarity::Positive,
),
hir::TraitBoundModifier::None => (None, ty::PredicatePolarity::Positive),
hir::TraitBoundModifier::Negative => {
(None, ty::PredicatePolarity::Negative)
}
hir::TraitBoundModifier::Maybe => continue,
let hir::TraitBoundModifiers { constness, polarity } = poly_trait_ref.modifiers;
// FIXME: We could pass these directly into `lower_poly_trait_ref`
// so that we could use these spans in diagnostics within that function...
let constness = match constness {
hir::BoundConstness::Never => None,
hir::BoundConstness::Always(_) => Some(ty::BoundConstness::Const),
hir::BoundConstness::Maybe(_) => Some(ty::BoundConstness::ConstIfConst),
};
let polarity = match polarity {
rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive,
rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative,
rustc_ast::BoundPolarity::Maybe(_) => continue,
};

let _ = self.lower_poly_trait_ref(
&poly_trait_ref.trait_ref,
poly_trait_ref.span,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut potential_assoc_types = Vec::new();
let dummy_self = self.tcx().types.trait_object_dummy_self;
for trait_bound in hir_trait_bounds.iter().rev() {
// FIXME: This doesn't handle `? const`.
if trait_bound.modifiers == hir::TraitBoundModifier::Maybe {
if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity {
continue;
}
if let GenericArgCountResult {
Expand Down
14 changes: 10 additions & 4 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use rustc_ast_pretty::pprust::{Comments, PrintState};
use rustc_hir::{
BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind,
HirId, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term,
TraitBoundModifier,
};
use rustc_span::FileName;
use rustc_span::source_map::SourceMap;
Expand Down Expand Up @@ -676,9 +675,16 @@ impl<'a> State<'a> {
}

fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef<'_>) {
// FIXME: This isn't correct!
if t.modifiers == TraitBoundModifier::Maybe {
self.word("?");
let hir::TraitBoundModifiers { constness, polarity } = t.modifiers;
match constness {
hir::BoundConstness::Never => {}
hir::BoundConstness::Always(_) => self.word("const"),
hir::BoundConstness::Maybe(_) => self.word("~const"),
}
match polarity {
hir::BoundPolarity::Positive => {}
hir::BoundPolarity::Negative(_) => self.word("!"),
hir::BoundPolarity::Maybe(_) => self.word("?"),
}
self.print_formal_generic_params(t.bound_generic_params);
self.print_trait_ref(&t.trait_ref);
Expand Down
5 changes: 1 addition & 4 deletions compiler/rustc_lint/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return };
for bound in &bounds[..] {
let def_id = bound.trait_ref.trait_def_id();
if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop))
// FIXME: ?Drop is not a thing.
&& bound.modifiers != hir::TraitBoundModifier::Maybe
{
if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop)) {
let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return };
cx.emit_span_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id });
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ fn suggest_changing_unsized_bound(
.enumerate()
.filter(|(_, bound)| {
if let hir::GenericBound::Trait(poly) = bound
&& poly.modifiers == hir::TraitBoundModifier::Maybe
&& let hir::BoundPolarity::Maybe(_) = poly.modifiers.polarity
&& poly.trait_ref.trait_def_id() == def_id
{
true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -894,7 +894,7 @@ fn foo(&self) -> Self::T { String::new() }
// FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.

let trait_bounds = bounds.iter().filter_map(|bound| match bound {
hir::GenericBound::Trait(ptr) if ptr.modifiers == hir::TraitBoundModifier::None => {
hir::GenericBound::Trait(ptr) if ptr.modifiers == hir::TraitBoundModifiers::NONE => {
Some(ptr)
}
_ => None,
Expand Down
4 changes: 2 additions & 2 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ fn clean_generic_bound<'tcx>(
hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)),
hir::GenericBound::Trait(ref t) => {
// `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
if t.modifiers == hir::TraitBoundModifier::MaybeConst
if let hir::BoundConstness::Maybe(_) = t.modifiers.constness
&& cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap())
{
return None;
Expand Down Expand Up @@ -263,7 +263,7 @@ fn clean_poly_trait_ref_with_constraints<'tcx>(
trait_: clean_trait_ref_with_constraints(cx, poly_trait_ref, constraints),
generic_params: clean_bound_vars(poly_trait_ref.bound_vars()),
},
hir::TraitBoundModifier::None,
hir::TraitBoundModifiers::NONE,
)
}

Expand Down
19 changes: 12 additions & 7 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1257,36 +1257,41 @@ impl Eq for Attributes {}

#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub(crate) enum GenericBound {
TraitBound(PolyTrait, hir::TraitBoundModifier),
TraitBound(PolyTrait, hir::TraitBoundModifiers),
Outlives(Lifetime),
/// `use<'a, T>` precise-capturing bound syntax
Use(Vec<Symbol>),
}

impl GenericBound {
pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
Self::sized_with(cx, hir::TraitBoundModifier::None)
Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
}

pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
Self::sized_with(cx, hir::TraitBoundModifier::Maybe)
Self::sized_with(cx, hir::TraitBoundModifiers {
polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
constness: hir::BoundConstness::Never,
})
}

fn sized_with(cx: &mut DocContext<'_>, modifier: hir::TraitBoundModifier) -> GenericBound {
fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
let did = cx.tcx.require_lang_item(LangItem::Sized, None);
let empty = ty::Binder::dummy(ty::GenericArgs::empty());
let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
inline::record_extern_fqn(cx, did, ItemType::Trait);
GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifier)
GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
}

pub(crate) fn is_trait_bound(&self) -> bool {
matches!(self, Self::TraitBound(..))
}

pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
use rustc_hir::TraitBoundModifier as TBM;
if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self
if let GenericBound::TraitBound(
PolyTrait { ref trait_, .. },
rustc_hir::TraitBoundModifiers::NONE,
) = *self
&& Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait()
{
return true;
Expand Down
14 changes: 7 additions & 7 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,13 +399,13 @@ impl clean::GenericBound {
) -> impl Display + 'a + Captures<'tcx> {
display_fn(move |f| match self {
clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()),
clean::GenericBound::TraitBound(ty, modifier) => {
f.write_str(match modifier {
hir::TraitBoundModifier::None => "",
hir::TraitBoundModifier::Maybe => "?",
hir::TraitBoundModifier::Negative => "!",
// `const` and `~const` trait bounds are experimental; don't render them.
hir::TraitBoundModifier::Const | hir::TraitBoundModifier::MaybeConst => "",
clean::GenericBound::TraitBound(ty, modifiers) => {
// `const` and `~const` trait bounds are experimental; don't render them.
let hir::TraitBoundModifiers { polarity, constness: _ } = modifiers;
f.write_str(match polarity {
hir::BoundPolarity::Positive => "",
hir::BoundPolarity::Maybe(_) => "?",
hir::BoundPolarity::Negative(_) => "!",
})?;
ty.print(cx).fmt(f)
}
Expand Down
24 changes: 11 additions & 13 deletions src/librustdoc/json/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,20 +552,18 @@ impl FromClean<clean::GenericBound> for GenericBound {
}

pub(crate) fn from_trait_bound_modifier(
modifier: rustc_hir::TraitBoundModifier,
modifiers: rustc_hir::TraitBoundModifiers,
) -> TraitBoundModifier {
use rustc_hir::TraitBoundModifier::*;
match modifier {
None => TraitBoundModifier::None,
Maybe => TraitBoundModifier::Maybe,
MaybeConst => TraitBoundModifier::MaybeConst,
// FIXME(const_trait_impl): Create rjt::TBM::Const and map to it once always-const bounds
// are less experimental.
Const => TraitBoundModifier::None,
// FIXME(negative-bounds): This bound should be rendered negative, but
// since that's experimental, maybe let's not add it to the rustdoc json
// API just now...
Negative => TraitBoundModifier::None,
use rustc_hir as hir;
let hir::TraitBoundModifiers { constness, polarity } = modifiers;
match (constness, polarity) {
(hir::BoundConstness::Never, hir::BoundPolarity::Positive) => TraitBoundModifier::None,
(hir::BoundConstness::Never, hir::BoundPolarity::Maybe(_)) => TraitBoundModifier::Maybe,
(hir::BoundConstness::Maybe(_), hir::BoundPolarity::Positive) => {
TraitBoundModifier::MaybeConst
}
// FIXME: Fill out the rest of this matrix.
_ => TraitBoundModifier::None,
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use clippy_utils::source::snippet;
use rustc_errors::{Applicability, SuggestionStyle};
use rustc_hir::def_id::DefId;
use rustc_hir::{
AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifier, TyKind,
AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifiers, TyKind,
WherePredicate,
};
use rustc_hir_analysis::lower_ty;
Expand Down Expand Up @@ -234,7 +234,7 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds
.iter()
.filter_map(|bound| {
if let GenericBound::Trait(poly_trait) = bound
&& let TraitBoundModifier::None = poly_trait.modifiers
&& let TraitBoundModifiers::NONE = poly_trait.modifiers
&& let [.., path] = poly_trait.trait_ref.path.segments
&& poly_trait.bound_generic_params.is_empty()
&& let Some(trait_def_id) = path.res.opt_def_id()
Expand Down Expand Up @@ -300,7 +300,7 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) {
// simply comparing trait `DefId`s won't be enough. We also need to compare the generics.
for (index, bound) in bounds.iter().enumerate() {
if let GenericBound::Trait(poly_trait) = bound
&& let TraitBoundModifier::None = poly_trait.modifiers
&& let TraitBoundModifiers::NONE = poly_trait.modifiers
&& let [.., path] = poly_trait.trait_ref.path.segments
&& let implied_args = path.args.map_or([].as_slice(), |a| a.args)
&& let implied_constraints = path.args.map_or([].as_slice(), |a| a.constraints)
Expand Down
Loading

0 comments on commit febb3f7

Please sign in to comment.