Skip to content

Commit

Permalink
add polarity
Browse files Browse the repository at this point in the history
  • Loading branch information
Bryanskiy committed Feb 27, 2024
1 parent 9afdb8d commit 8226783
Show file tree
Hide file tree
Showing 30 changed files with 200 additions and 88 deletions.
28 changes: 13 additions & 15 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1255,6 +1255,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
itctx,
TraitBoundModifiers::NONE,
);
let bound = (bound, hir::TraitBoundModifier::None);
let bounds = this.arena.alloc_from_iter([bound]);
let lifetime_bound = this.elided_dyn_bound(t.span);
(bounds, lifetime_bound)
Expand Down Expand Up @@ -1386,21 +1387,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// We can safely ignore constness here since AST validation
// takes care of rejecting invalid modifier combinations and
// const trait bounds in trait object types.
GenericBound::Trait(ty, modifiers) => match modifiers.polarity {
BoundPolarity::Positive | BoundPolarity::Negative(_) => {
Some(this.lower_poly_trait_ref(
ty,
itctx,
// Still, don't pass along the constness here; we don't want to
// synthesize any host effect args, it'd only cause problems.
TraitBoundModifiers {
constness: BoundConstness::Never,
..*modifiers
},
))
}
BoundPolarity::Maybe(_) => None,
},
GenericBound::Trait(ty, modifiers) => {
// Still, don't pass along the constness here; we don't want to
// synthesize any host effect args, it'd only cause problems.
let modifiers = TraitBoundModifiers {
constness: BoundConstness::Never,
..*modifiers
};
let trait_ref = this.lower_poly_trait_ref(ty, itctx, modifiers);
let polarity = this.lower_trait_bound_modifiers(modifiers);
Some((trait_ref, polarity))
}
GenericBound::Outlives(lifetime) => {
if lifetime_bound.is_none() {
lifetime_bound = Some(this.lower_lifetime(lifetime));
Expand Down Expand Up @@ -2502,6 +2499,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
trait_ref: hir::TraitRef { path, hir_ref_id: hir_id },
span: self.lower_span(span),
};
let principal = (principal, hir::TraitBoundModifier::None);

// The original ID is taken by the `PolyTraitRef`,
// so the `Ty` itself needs a different one.
Expand Down
5 changes: 0 additions & 5 deletions compiler/rustc_ast_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,6 @@ ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier
ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax
.help = use `auto trait Trait {"{}"}` instead
ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types
ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits
.note = traits are `?{$path_str}` by default
ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters
.suggestion = reorder the parameters: lifetimes, then consts and types
Expand Down
10 changes: 1 addition & 9 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1260,16 +1260,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {

fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
if let GenericBound::Trait(poly, modifiers) = bound {
// Some of the arms are feature-gated. See `feature_gate::PostExpansionVisitor`.
match (ctxt, modifiers.constness, modifiers.polarity) {
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
self.dcx().emit_err(errors::OptionalTraitSupertrait {
span: poly.span,
path_str: pprust::path_to_string(&poly.trait_ref.path),
});
}
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span });
}
(BoundKind::TraitObject, BoundConstness::Always(_), BoundPolarity::Positive) => {
self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span });
}
Expand Down
16 changes: 0 additions & 16 deletions compiler/rustc_ast_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,22 +543,6 @@ pub struct NestedLifetimes {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(ast_passes_optional_trait_supertrait)]
#[note]
pub struct OptionalTraitSupertrait {
#[primary_span]
pub span: Span,
pub path_str: String,
}

#[derive(Diagnostic)]
#[diag(ast_passes_optional_trait_object)]
pub struct OptionalTraitObject {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(ast_passes_const_bound_trait_object)]
pub struct ConstBoundTraitObject {
Expand Down
21 changes: 21 additions & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,27 @@ impl<'a> PostExpansionVisitor<'a> {
}

impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
fn visit_param_bound(&mut self, bound: &'a ast::GenericBound, ctxt: visit::BoundKind) {
use ast::visit::BoundKind;
use ast::{BoundConstness, BoundPolarity};
if let ast::GenericBound::Trait(poly, modifiers) = bound {
let gate = |descr| {
gate!(&self, allow_maybe_polarity, poly.span, descr);
};

match (ctxt, modifiers.constness, modifiers.polarity) {
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
gate("`?Trait` is not permitted in trait object types");
}
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
gate("`?Trait` is not permitted in supertraits");
}
_ => {}
}
}
visit::walk_param_bound(self, bound);
}

fn visit_attribute(&mut self, attr: &ast::Attribute) {
let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
// Check feature gates for built-in attributes.
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ declare_features! (
/// below (it has to be checked before expansion possibly makes
/// macros disappear).
(internal, allow_internal_unstable, "1.0.0", None),
/// Allows using `?Trait` trait bound.
(internal, allow_maybe_polarity, "CURRENT_RUSTC_VERSION", None),
/// Allows using anonymous lifetimes in argument-position impl-trait.
(unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None),
/// Allows identifying the `compiler_builtins` crate.
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2603,7 +2603,11 @@ pub enum TyKind<'hir> {
OpaqueDef(ItemId, &'hir [GenericArg<'hir>], bool),
/// A trait object type `Bound1 + Bound2 + Bound3`
/// where `Bound` is a trait or a lifetime.
TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
TraitObject(
&'hir [(PolyTraitRef<'hir>, TraitBoundModifier)],
&'hir Lifetime,
TraitObjectSyntax,
),
/// Unused for now.
Typeof(AnonConst),
/// `TyKind::Infer` means the type should be inferred instead of it having been
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
try_visit!(visitor.visit_array_length(length));
}
TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
walk_list!(visitor, visit_poly_trait_ref, bounds);
for (bound, _) in bounds {
try_visit!(visitor.visit_poly_trait_ref(bound));
}
try_visit!(visitor.visit_lifetime(lifetime));
}
TyKind::Typeof(ref expression) => try_visit!(visitor.visit_anon_const(expression)),
Expand Down
14 changes: 8 additions & 6 deletions compiler/rustc_hir_analysis/src/astconv/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
}
}

if unbounds.len() > 1 {
if unbounds.len() > 1 && !tcx.features().allow_maybe_polarity {
tcx.dcx().emit_err(errors::MultipleRelaxedDefaultBounds {
spans: unbounds.iter().map(|ptr| ptr.span).collect(),
});
Expand All @@ -80,12 +80,14 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
seen_sized_unbound = true;
continue;
}
// There was a `?Trait` bound, but it was not `?Sized`; warn.
tcx.dcx().span_warn(
unbound.span,
"relaxing a default bound only does something for `?Sized`; \
if !tcx.features().allow_maybe_polarity {
// There was a `?Trait` bound, but it was not `?Sized`; warn.
tcx.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 {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_hir_analysis/src/astconv/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&self,
associated_types: FxIndexMap<Span, FxIndexSet<DefId>>,
potential_assoc_types: Vec<Span>,
trait_bounds: &[hir::PolyTraitRef<'_>],
trait_bounds: &[(hir::PolyTraitRef<'_>, hir::TraitBoundModifier)],
) {
if associated_types.values().all(|v| v.is_empty()) {
return;
Expand Down Expand Up @@ -634,7 +634,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if object_safety_violations {
return;
}
if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
if let ([], [(bound, _)]) = (&potential_assoc_types[..], &trait_bounds) {
match bound.trait_ref.path.segments {
// FIXME: `trait_ref.path.span` can point to a full path with multiple
// segments, even though `trait_ref.path.segments` is of length `1`. Work
Expand Down Expand Up @@ -676,7 +676,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// and we can then use their span to indicate this to the user.
let bound_names = trait_bounds
.iter()
.filter_map(|poly_trait_ref| {
.filter_map(|(poly_trait_ref, _)| {
let path = poly_trait_ref.trait_ref.path.segments.last()?;
let args = path.args?;

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/astconv/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut is_downgradable = true;
let is_object_safe = match self_ty.kind {
hir::TyKind::TraitObject(objects, ..) => {
objects.iter().all(|o| match o.trait_ref.path.res {
objects.iter().all(|(o, _)| match o.trait_ref.path.res {
Res::Def(DefKind::Trait, id) => {
if Some(id) == owner {
// For recursive traits, don't downgrade the error. (#119652)
Expand Down Expand Up @@ -192,7 +192,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {

pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
let tcx = self.tcx();
if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
if let hir::TyKind::TraitObject([(poly_trait_ref, _), ..], _, TraitObjectSyntax::None) =
self_ty.kind
{
let needs_bracket = in_path
Expand Down
9 changes: 6 additions & 3 deletions compiler/rustc_hir_analysis/src/astconv/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&self,
span: Span,
hir_id: hir::HirId,
hir_trait_bounds: &[hir::PolyTraitRef<'tcx>],
hir_trait_bounds: &[(hir::PolyTraitRef<'tcx>, hir::TraitBoundModifier)],
lifetime: &hir::Lifetime,
borrowed: bool,
representation: DynKind,
Expand All @@ -32,7 +32,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut bounds = Bounds::default();
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() {
for (trait_bound, modifier) in hir_trait_bounds.iter().rev() {
if *modifier == hir::TraitBoundModifier::Maybe {
continue;
}
if let GenericArgCountResult {
correct:
Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }),
Expand Down Expand Up @@ -279,7 +282,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let args = tcx.mk_args(&args);

let span = i.bottom().1;
let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
let empty_generic_args = hir_trait_bounds.iter().any(|(hir_bound, _)| {
hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
&& hir_bound.span.contains(span)
});
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GATArgsCollector<'tcx> {

fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
match ty.kind {
hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments {
hir::TyKind::TraitObject([(trait_ref, _)], ..) => match trait_ref.trait_ref.path.segments {
[s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()),
_ => false,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
debug!(?bounds, ?lifetime, "TraitObject");
let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |this| {
for bound in bounds {
for (bound, modifier) in bounds {
if *modifier == hir::TraitBoundModifier::Maybe {
continue;
}
this.visit_poly_trait_ref_inner(
bound,
NonLifetimeBinderAllowed::Deny("trait object types"),
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,13 +293,16 @@ impl<'a> State<'a> {
self.word_space("dyn");
}
let mut first = true;
for bound in bounds {
for (bound, modifier) in bounds {
if first {
first = false;
} else {
self.nbsp();
self.word_space("+");
}
if *modifier == TraitBoundModifier::Maybe {
self.word("?");
}
self.print_poly_trait_ref(bound);
}
if !lifetime.is_elided() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
}

hir::TyKind::TraitObject(bounds, ..) => {
for bound in bounds {
for (bound, _) in bounds {
self.current_index.shift_in(1);
self.visit_poly_trait_ref(bound);
self.current_index.shift_out(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> {
_,
) = t.kind
{
for ptr in poly_trait_refs {
for (ptr, _) in poly_trait_refs {
if Some(self.1) == ptr.trait_ref.trait_def_id() {
self.0.push(ptr.span);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_infer/src/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub fn report_object_safety_error<'tcx>(

if let Some(hir_id) = hir_id
&& let hir::Node::Ty(ty) = tcx.hir_node(hir_id)
&& let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind
&& let hir::TyKind::TraitObject([(trait_ref, _), ..], ..) = ty.kind
{
let mut hir_id = hir_id;
while let hir::Node::Ty(ty) = tcx.parent_hir_node(hir_id) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/non_local_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
TyKind::Path(QPath::Resolved(_, ty_path)) => {
path_has_local_parent(ty_path, cx, &*local_parents)
}
TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => {
TyKind::TraitObject([(principle_poly_trait_ref, _), ..], _, _) => {
path_has_local_parent(
principle_poly_trait_ref.trait_ref.path,
cx,
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_lint/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,11 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {

fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return };
for bound in &bounds[..] {
for (bound, modifier) in &bounds[..] {
let def_id = bound.trait_ref.trait_def_id();
if cx.tcx.lang_items().drop_trait() == def_id {
if cx.tcx.lang_items().drop_trait() == def_id
&& *modifier != hir::TraitBoundModifier::Maybe
{
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
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ symbols! {
allow_fail,
allow_internal_unsafe,
allow_internal_unstable,
allow_maybe_polarity,
alu32,
always,
and,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2994,11 +2994,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
match ty.kind {
hir::TyKind::TraitObject(traits, _, _) => {
let (span, kw) = match traits {
[first, ..] if first.span.lo() == ty.span.lo() => {
[(first, _), ..] if first.span.lo() == ty.span.lo() => {
// Missing `dyn` in front of trait object.
(ty.span.shrink_to_lo(), "dyn ")
}
[first, ..] => (ty.span.until(first.span), ""),
[(first, _), ..] => (ty.span.until(first.span), ""),
[] => span_bug!(ty.span, "trait object with no traits: {ty:?}"),
};
let needs_parens = traits.len() != 1;
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1859,7 +1859,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
}
TyKind::Path(_) => clean_qpath(ty, cx),
TyKind::TraitObject(bounds, ref lifetime, _) => {
let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect();
let bounds = bounds.iter().map(|(bound, _)| clean_poly_trait_ref(bound, cx)).collect();
let lifetime =
if !lifetime.is_elided() { Some(clean_lifetime(*lifetime, cx)) } else { None };
DynTrait(bounds, lifetime)
Expand Down
Loading

0 comments on commit 8226783

Please sign in to comment.