Add MaybeConst variant to {ast,hir}::TraitBoundModifier

This commit is contained in:
Dylan MacKenzie 2020-01-13 20:30:27 -08:00
parent 958b0bc8d2
commit eb60346cc9
6 changed files with 42 additions and 32 deletions

View File

@ -1250,7 +1250,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let bounds =
this.arena.alloc_from_iter(bounds.iter().filter_map(
|bound| match *bound {
GenericBound::Trait(ref ty, TraitBoundModifier::None) => {
GenericBound::Trait(ref ty, TraitBoundModifier::None)
| GenericBound::Trait(ref ty, TraitBoundModifier::MaybeConst) => {
Some(this.lower_poly_trait_ref(ty, itctx.reborrow()))
}
GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
@ -2158,10 +2159,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
p: &PolyTraitRef,
mut itctx: ImplTraitContext<'_, 'hir>,
) -> hir::PolyTraitRef<'hir> {
if p.trait_ref.constness.is_some() {
self.diagnostic().span_err(p.span, "`?const` on trait bounds is not yet implemented");
}
let bound_generic_params = self.lower_generic_params(
&p.bound_generic_params,
&NodeMap::default(),
@ -2301,6 +2298,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
match f {
TraitBoundModifier::None => hir::TraitBoundModifier::None,
TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe,
TraitBoundModifier::MaybeConst => hir::TraitBoundModifier::MaybeConst,
}
}

View File

@ -917,22 +917,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
fn visit_param_bound(&mut self, bound: &'a GenericBound) {
if let GenericBound::Trait(poly, maybe_bound) = bound {
match poly.trait_ref.constness {
Some(Constness::NotConst) => {
if *maybe_bound == TraitBoundModifier::Maybe {
self.err_handler()
.span_err(bound.span(), "`?const` and `?` are mutually exclusive");
}
if let Some(ctx) = self.bound_context {
let msg = format!("`?const` is not permitted in {}", ctx.description());
self.err_handler().span_err(bound.span(), &msg);
}
}
Some(Constness::Const) => panic!("Parser should reject bare `const` on bounds"),
None => {}
if let GenericBound::Trait(_, TraitBoundModifier::MaybeConst) = bound {
if let Some(ctx) = self.bound_context {
let msg = format!("`?const` is not permitted in {}", ctx.description());
self.err_handler().span_err(bound.span(), &msg);
}
}

View File

@ -364,6 +364,7 @@ impl GenericArgs<'_> {
pub enum TraitBoundModifier {
None,
Maybe,
MaybeConst,
}
/// The AST represents all type param bounds as types.

View File

@ -27,11 +27,17 @@ struct BoundModifiers {
}
impl BoundModifiers {
fn trait_bound_modifier(&self) -> TraitBoundModifier {
match self.maybe {
Some(_) => TraitBoundModifier::Maybe,
None => TraitBoundModifier::None,
}
fn to_trait_bound_modifier(&self) -> Result<TraitBoundModifier, &'static str> {
let modifier = match (self.maybe, self.maybe_const) {
(None, None) => TraitBoundModifier::None,
(Some(_), None) => TraitBoundModifier::Maybe,
(None, Some(_)) => TraitBoundModifier::MaybeConst,
(Some(_), Some(_)) => {
return Err("`?const` and `?` are mutually exclusive");
}
};
Ok(modifier)
}
}
@ -215,7 +221,7 @@ impl<'a> Parser<'a> {
) -> PResult<'a, TyKind> {
assert_ne!(self.token, token::Question);
let poly_trait_ref = PolyTraitRef::new(generic_params, path, None, lo.to(self.prev_span));
let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span));
let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)];
if parse_plus {
self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
@ -557,9 +563,18 @@ impl<'a> Parser<'a> {
self.expect(&token::CloseDelim(token::Paren))?;
}
let constness = modifiers.maybe_const.map(|_| ast::Constness::NotConst);
let poly_trait = PolyTraitRef::new(lifetime_defs, path, constness, lo.to(self.prev_span));
Ok(GenericBound::Trait(poly_trait, modifiers.trait_bound_modifier()))
let modifier = match modifiers.to_trait_bound_modifier() {
Ok(m) => m,
Err(msg) => {
self.struct_span_err(lo.to(self.prev_span), msg).emit();
// Continue compilation as if the user had written `?Trait`.
TraitBoundModifier::Maybe
}
};
let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
Ok(GenericBound::Trait(poly_trait, modifier))
}
/// Optionally parses `for<$generic_params>`.

View File

@ -361,6 +361,7 @@ impl clean::GenericBound {
let modifier_str = match modifier {
hir::TraitBoundModifier::None => "",
hir::TraitBoundModifier::Maybe => "?",
hir::TraitBoundModifier::MaybeConst => "?const",
};
if f.alternate() {
write!(f, "{}{:#}", modifier_str, ty.print())

View File

@ -266,12 +266,19 @@ pub const CRATE_NODE_ID: NodeId = NodeId::from_u32_const(0);
/// small, positive ids.
pub const DUMMY_NODE_ID: NodeId = NodeId::MAX;
/// A modifier on a bound, currently this is only used for `?Sized`, where the
/// modifier is `Maybe`. Negative bounds should also be handled here.
/// A modifier on a bound, e.g., `?Sized` or `?const Trait`.
///
/// Negative bounds should also be handled here.
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
pub enum TraitBoundModifier {
/// No modifiers
None,
/// `?Trait`
Maybe,
/// `?const Trait`
MaybeConst,
}
/// The AST represents all type param bounds as types.