Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3179,6 +3179,8 @@ pub enum BoundPolarity {
Negative(Span),
/// `Type: ?Trait`
Maybe(Span),
/// `Type: only Trait`,
Only(Span),
}

impl BoundPolarity {
Expand All @@ -3187,6 +3189,7 @@ impl BoundPolarity {
Self::Positive => "",
Self::Negative(_) => "!",
Self::Maybe(_) => "?",
Self::Only(_) => "only",
}
}
}
Expand Down
15 changes: 15 additions & 0 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2219,6 +2219,8 @@ impl<'hir> LoweringContext<'_, 'hir> {

if let ast::BoundPolarity::Maybe(_) = modifiers.polarity {
self.validate_relaxed_bound(trait_ref, *span, rbp);
} else if let ast::BoundPolarity::Only(_) = modifiers.polarity {
self.validate_only_bound(trait_ref, *span);
}

hir::PolyTraitRef {
Expand All @@ -2229,6 +2231,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}

fn validate_only_bound(&self, trait_ref: hir::TraitRef<'_>, span: Span) {
if let Res::Def(DefKind::Trait, def_id) = trait_ref.path.res
&& !(self.tcx.is_lang_item(def_id, hir::LangItem::MetaSized)
|| self.tcx.is_lang_item(def_id, hir::LangItem::Sized)
|| self.tcx.is_lang_item(def_id, hir::LangItem::PointeeSized))
{
self.dcx()
.struct_span_err(span, "`only` may only be applied to sizedness traits")
.emit();
}
}

fn validate_relaxed_bound(
&self,
trait_ref: hir::TraitRef<'_>,
Expand Down Expand Up @@ -2778,6 +2792,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
BoundPolarity::Positive => BoundPolarity::Positive,
BoundPolarity::Negative(span) => BoundPolarity::Negative(self.lower_span(span)),
BoundPolarity::Maybe(span) => BoundPolarity::Maybe(self.lower_span(span)),
BoundPolarity::Only(span) => BoundPolarity::Only(self.lower_span(span)),
};
hir::TraitBoundModifiers { constness, polarity }
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1478,7 +1478,9 @@ impl<'a> State<'a> {
}
match polarity {
ast::BoundPolarity::Positive => {}
ast::BoundPolarity::Negative(_) | ast::BoundPolarity::Maybe(_) => {
ast::BoundPolarity::Negative(_)
| ast::BoundPolarity::Maybe(_)
| ast::BoundPolarity::Only(_) => {
self.word(polarity.as_str());
}
}
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ struct CollectedBound {
maybe: bool,
/// `!Trait`
negative: bool,
/// `only Trait`
only_modifier: bool,
}

impl CollectedBound {
/// Returns `true` if any of `Trait`, `?Trait` or `!Trait` were encountered.
/// Returns `true` if any of `Trait`, `?Trait`, `only Trait` or `!Trait` were encountered.
fn any(&self) -> bool {
self.positive || self.maybe || self.negative
self.positive || self.maybe || self.negative || self.only_modifier
}
}

Expand Down Expand Up @@ -112,6 +114,7 @@ fn collect_bounds<'a, 'tcx>(
match ptr.modifiers.polarity {
hir::BoundPolarity::Maybe(_) => collect_into.maybe = true,
hir::BoundPolarity::Negative(_) => collect_into.negative = true,
hir::BoundPolarity::Only(_) => collect_into.only_modifier = true,
hir::BoundPolarity::Positive => collect_into.positive = true,
}
});
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// we still need to perform several validation steps (see below). Instead, simply "pour" all
// resulting bounds "down the drain", i.e., into a new `Vec` that just gets dropped at the end.
let transient = match polarity {
hir::BoundPolarity::Positive => {
hir::BoundPolarity::Positive | hir::BoundPolarity::Only(_) => {
// To elaborate on the comment directly above, regarding `PointeeSized` specifically,
// we don't "reify" such bounds to avoid trait system limitations -- namely,
// non-global where-clauses being preferred over item bounds (where `PointeeSized`
Expand All @@ -990,9 +990,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let bounds = if transient { &mut Vec::new() } else { bounds };

let polarity = match polarity {
hir::BoundPolarity::Positive | hir::BoundPolarity::Maybe(_) => {
ty::PredicatePolarity::Positive
}
hir::BoundPolarity::Positive
| hir::BoundPolarity::Maybe(_)
| hir::BoundPolarity::Only(_) => ty::PredicatePolarity::Positive,
hir::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative,
};

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,7 @@ impl<'a> State<'a> {
hir::BoundPolarity::Positive => {}
hir::BoundPolarity::Negative(_) => self.word("!"),
hir::BoundPolarity::Maybe(_) => self.word("?"),
hir::BoundPolarity::Only(_) => self.word_space("only"),
}
self.print_formal_generic_params(t.bound_generic_params);
self.print_trait_ref(&t.trait_ref);
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_parse/src/parser/token_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ pub enum TokenType {
KwMod,
KwMove,
KwMut,
KwOnly,
KwPub,
KwRaw,
KwRef,
Expand Down Expand Up @@ -247,6 +248,7 @@ impl TokenType {
KwMod,
KwMove,
KwMut,
KwOnly,
KwPub,
KwRaw,
KwRef,
Expand Down Expand Up @@ -324,6 +326,7 @@ impl TokenType {
TokenType::KwMod => Some(kw::Mod),
TokenType::KwMove => Some(kw::Move),
TokenType::KwMut => Some(kw::Mut),
TokenType::KwOnly => Some(kw::Only),
TokenType::KwPub => Some(kw::Pub),
TokenType::KwRaw => Some(kw::Raw),
TokenType::KwRef => Some(kw::Ref),
Expand Down Expand Up @@ -540,6 +543,7 @@ macro_rules! exp {
(Mod) => { exp!(@kw, Mod, KwMod) };
(Move) => { exp!(@kw, Move, KwMove) };
(Mut) => { exp!(@kw, Mut, KwMut) };
(Only) => { exp!(@kw, Only, KwOnly) };
(Pub) => { exp!(@kw, Pub, KwPub) };
(Raw) => { exp!(@kw, Raw, KwRaw) };
(Ref) => { exp!(@kw, Ref, KwRef) };
Expand Down
15 changes: 12 additions & 3 deletions compiler/rustc_parse/src/parser/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,7 @@ impl<'a> Parser<'a> {
|| self.check(exp!(OpenParen))
|| self.can_begin_maybe_const_bound()
|| self.check_keyword(exp!(Const))
|| self.check_keyword(exp!(Only))
|| self.check_keyword(exp!(Async))
|| self.check_keyword(exp!(Use))
}
Expand Down Expand Up @@ -1201,7 +1202,9 @@ impl<'a> Parser<'a> {

match polarity {
BoundPolarity::Positive => {}
BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => {
BoundPolarity::Negative(span)
| BoundPolarity::Maybe(span)
| BoundPolarity::Only(span) => {
return self
.dcx()
.emit_err(errors::ModifierLifetime { span, modifier: polarity.as_str() });
Expand Down Expand Up @@ -1265,6 +1268,8 @@ impl<'a> Parser<'a> {
} else if self.eat(exp!(Bang)) {
self.psess.gated_spans.gate(sym::negative_bounds, self.prev_token.span);
BoundPolarity::Negative(self.prev_token.span)
} else if self.eat_keyword(exp!(Only)) {
BoundPolarity::Only(self.prev_token.span)
} else {
BoundPolarity::Positive
};
Expand All @@ -1274,7 +1279,9 @@ impl<'a> Parser<'a> {
BoundPolarity::Positive => {
// All trait bound modifiers allowed to combine with positive polarity
}
BoundPolarity::Maybe(polarity_span) | BoundPolarity::Negative(polarity_span) => {
BoundPolarity::Maybe(polarity_span)
| BoundPolarity::Negative(polarity_span)
| BoundPolarity::Only(polarity_span) => {
match (asyncness, constness) {
(BoundAsyncness::Normal, BoundConstness::Never) => {
// Ok, no modifiers.
Expand Down Expand Up @@ -1346,7 +1353,9 @@ impl<'a> Parser<'a> {

if let Some(binder_span) = binder_span {
match modifiers.polarity {
BoundPolarity::Negative(polarity_span) | BoundPolarity::Maybe(polarity_span) => {
BoundPolarity::Negative(polarity_span)
| BoundPolarity::Maybe(polarity_span)
| BoundPolarity::Only(polarity_span) => {
self.dcx().emit_err(errors::BinderAndPolarity {
binder_span,
polarity_span,
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 @@ -129,6 +129,7 @@ symbols! {
ContractRequires: "contract_requires",
Default: "default",
MacroRules: "macro_rules",
Only: "only",
Raw: "raw",
Reuse: "reuse",
Safe: "safe",
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ pub(crate) fn print_generic_bound(
hir::BoundPolarity::Positive => "",
hir::BoundPolarity::Maybe(_) => "?",
hir::BoundPolarity::Negative(_) => "!",
hir::BoundPolarity::Only(_) => "only",
})?;
print_poly_trait(ty, cx).fmt(f)
}
Expand Down
1 change: 1 addition & 0 deletions src/tools/clippy/clippy_utils/src/check_proc_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,7 @@ fn poly_trait_ref_search_pat(poly_trait_ref: &PolyTraitRef<'_>) -> (Pat, Pat) {
.or_else(|| match polarity {
BoundPolarity::Negative(_) => Some(Pat::Str("!")),
BoundPolarity::Maybe(_) => Some(Pat::Str("?")),
BoundPolarity::Only(_) => Some(Pat::Str("only")),
BoundPolarity::Positive => None,
})
.unwrap_or(trait_ref_search_pat.0);
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/parser/trait-object-delimiters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around t
fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around trait bounds

fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{`
//~^ ERROR expected one of `!`, `(`, `)`, `,`, `?`, `[`, `async`, `const`, `for`, `use`, `~`, lifetime, or path, found `{`
//~^ ERROR expected one of `!`, `(`, `)`, `,`, `?`, `[`, `async`, `const`, `for`, `only`, `use`, `~`, lifetime, or path, found `{`
//~| ERROR at least one trait is required for an object type

fn foo4(_: &dyn <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<`
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/parser/trait-object-delimiters.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ error: expected parameter name, found `{`
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
| ^ expected parameter name

error: expected one of `!`, `(`, `)`, `,`, `?`, `[`, `async`, `const`, `for`, `use`, `~`, lifetime, or path, found `{`
error: expected one of `!`, `(`, `)`, `,`, `?`, `[`, `async`, `const`, `for`, `only`, `use`, `~`, lifetime, or path, found `{`
--> $DIR/trait-object-delimiters.rs:10:17
|
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
| -^ expected one of 13 possible tokens
| -^ expected one of 14 possible tokens
| |
| help: missing `,`

Expand Down
86 changes: 86 additions & 0 deletions tests/ui/trait-bounds/only-bound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#![feature(sized_hierarchy)]
use std::marker::{MetaSized, PointeeSized};
use std::mem::{size_of, size_of_val};
use std::fmt::Debug;

fn foo<T: only Sized>(t: T) {
size_of::<T>();
size_of_val(&t);
}

fn bar<T: only MetaSized>(t: T) {
//~^ ERROR the size for values of type `T` cannot be known at compilation time
size_of::<T>();
size_of_val(&t);
}

fn barfoo<T: only PointeeSized>(t: T) {
//~^ ERROR the size for values of type `T` cannot be known at compilation time
size_of::<T>();
size_of_val(&t);
//~^ ERROR the size for values of type `T` cannot be known
}

trait OnlyPointeeSized: only PointeeSized {
fn foo(&self) {
size_of_val(self);
//~^ ERROR the size for values of type `Self` cannot be known
}
}

trait NonSizedOnly1: only Debug {}
//~^ ERROR `only` may only be applied to sizedness traits

trait Trait {}

trait NonSizedOnly2: only Trait {}
//~^ ERROR `only` may only be applied to sizedness traits

trait OnlyOnly: only OnlyPointeeSized {}
//~^ ERROR `only` may only be applied to sizedness traits

trait DoubleOnly: only PointeeSized + only MetaSized {}
// Redundant, but not illegal.

trait InheritedOnly: OnlyPointeeSized {
fn foo(&self) {
size_of_val(self);
// This works fine, `only` is not transitive, this trait still has the
// `MetaSized` default supertrait.
}
}



fn only(){
let only = 0u32;
}

mod a{
#[allow(non_camel_case_types)]
struct only {}
}

mod b {
use std::marker::{MetaSized, PointeeSized};

#[allow(non_camel_case_types)]
trait only: only PointeeSized {
fn foo(&self) {
size_of_val(self);
//~^ ERROR the size for values of type `Self` cannot be known
}
}
}

mod only{
pub trait Alpha {}
}

// In the below context, rust will attempt to look for `Alpha` in the crate root, not in a module
// `only`
//fn alpha<T: only::Alpha>(){
//}


fn main() {}
Loading
Loading