Skip to content

Commit

Permalink
add polarity
Browse files Browse the repository at this point in the history
  • Loading branch information
Bryanskiy committed Mar 1, 2024
1 parent 9afdb8d commit 540fde9
Show file tree
Hide file tree
Showing 40 changed files with 258 additions and 114 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: 20 additions & 1 deletion compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use rustc_ast as ast;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
use rustc_ast::{attr, AssocConstraint, AssocConstraintKind, NodeId};
use rustc_ast::{PatKind, RangeEnd};
use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
Expand Down Expand Up @@ -169,6 +169,25 @@ impl<'a> PostExpansionVisitor<'a> {
}

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

match (ctxt, modifiers.polarity) {
(BoundKind::TraitObject, ast::BoundPolarity::Maybe(_)) => {
gate("`?Trait` is not permitted in trait object types");
}
(BoundKind::SuperTraits, ast::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
6 changes: 4 additions & 2 deletions compiler/rustc_error_codes/src/error_codes/E0203.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#### Note: this error code is no longer emitted by the compiler.

Having multiple relaxed default bounds is unsupported.

Erroneous code example:
Previously erroneous code example:

```compile_fail,E0203
```compile_fail
struct Bad<T: ?Sized + ?Send>{
inner: T
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_error_codes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,7 @@ E0797: 0797,
// E0190, // deprecated: can only cast a &-pointer to an &-object
// E0194, // merged into E0403
// E0196, // cannot determine a type for this closure
// E0203 // replaced with a `more_maybe_bounds` feature gate
// E0209, // builtin traits can only be implemented on structs or enums
// E0213, // associated types are not accepted in this context
// E0215, // angle-bracket notation is not stable with `Fn`
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 @@ -207,6 +207,8 @@ declare_features! (
(unstable, lifetime_capture_rules_2024, "1.76.0", None),
/// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406
(unstable, link_cfg, "1.14.0", None),
/// Allows using `?Trait` trait bounds in more contexts.
(internal, more_maybe_bounds, "CURRENT_RUSTC_VERSION", None),
/// Allows the `multiple_supertrait_upcastable` lint.
(unstable, multiple_supertrait_upcastable, "1.69.0", None),
/// Allow negative trait bounds. This is an internal-only feature for testing the trait solver!
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, _modifier) 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
3 changes: 0 additions & 3 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,6 @@ hir_analysis_missing_type_params =
} to {$parameters}
.note = because of the default `Self` reference, type parameters must be specified on object types
hir_analysis_multiple_relaxed_default_bounds =
type parameter has more than one relaxed default bound, only one is supported
hir_analysis_must_be_name_of_associated_function = must be a name of an associated function
hir_analysis_must_implement_not_function = not a function
Expand Down
15 changes: 10 additions & 5 deletions compiler/rustc_hir_analysis/src/astconv/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::ty::{self as ty, Ty};
use rustc_session::parse::feature_err;
use rustc_span::symbol::Ident;
use rustc_span::{ErrorGuaranteed, Span};
use rustc_span::{sym, ErrorGuaranteed, Span};
use rustc_trait_selection::traits;
use smallvec::SmallVec;

Expand Down Expand Up @@ -66,10 +67,14 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
}
}

if unbounds.len() > 1 {
tcx.dcx().emit_err(errors::MultipleRelaxedDefaultBounds {
spans: unbounds.iter().map(|ptr| ptr.span).collect(),
});
if unbounds.len() > 1 && !tcx.features().more_maybe_bounds {
feature_err(
tcx.sess,
sym::more_maybe_bounds,
unbounds.iter().map(|ptr| ptr.span).collect::<Vec<Span>>(),
"type parameter has more than one relaxed default bound, only one is supported",
)
.emit();
}

let mut seen_sized_unbound = false;
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,7 @@ 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, _) in bounds {
this.visit_poly_trait_ref_inner(
bound,
NonLifetimeBinderAllowed::Deny("trait object types"),
Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,13 +246,6 @@ pub struct CopyImplOnTypeWithDtor {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_multiple_relaxed_default_bounds, code = E0203)]
pub struct MultipleRelaxedDefaultBounds {
#[primary_span]
pub spans: Vec<Span>,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_copy_impl_on_non_adt, code = E0206)]
pub struct CopyImplOnNonAdt {
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
Loading

0 comments on commit 540fde9

Please sign in to comment.