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 = let bounds =
this.arena.alloc_from_iter(bounds.iter().filter_map( this.arena.alloc_from_iter(bounds.iter().filter_map(
|bound| match *bound { |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())) Some(this.lower_poly_trait_ref(ty, itctx.reborrow()))
} }
GenericBound::Trait(_, TraitBoundModifier::Maybe) => None, GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
@ -2158,10 +2159,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
p: &PolyTraitRef, p: &PolyTraitRef,
mut itctx: ImplTraitContext<'_, 'hir>, mut itctx: ImplTraitContext<'_, 'hir>,
) -> hir::PolyTraitRef<'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( let bound_generic_params = self.lower_generic_params(
&p.bound_generic_params, &p.bound_generic_params,
&NodeMap::default(), &NodeMap::default(),
@ -2301,6 +2298,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
match f { match f {
TraitBoundModifier::None => hir::TraitBoundModifier::None, TraitBoundModifier::None => hir::TraitBoundModifier::None,
TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe, 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) { fn visit_param_bound(&mut self, bound: &'a GenericBound) {
if let GenericBound::Trait(poly, maybe_bound) = bound { if let GenericBound::Trait(_, TraitBoundModifier::MaybeConst) = bound {
match poly.trait_ref.constness { if let Some(ctx) = self.bound_context {
Some(Constness::NotConst) => { let msg = format!("`?const` is not permitted in {}", ctx.description());
if *maybe_bound == TraitBoundModifier::Maybe { self.err_handler().span_err(bound.span(), &msg);
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 => {}
} }
} }

View File

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

View File

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

View File

@ -361,6 +361,7 @@ impl clean::GenericBound {
let modifier_str = match modifier { let modifier_str = match modifier {
hir::TraitBoundModifier::None => "", hir::TraitBoundModifier::None => "",
hir::TraitBoundModifier::Maybe => "?", hir::TraitBoundModifier::Maybe => "?",
hir::TraitBoundModifier::MaybeConst => "?const",
}; };
if f.alternate() { if f.alternate() {
write!(f, "{}{:#}", modifier_str, ty.print()) 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. /// small, positive ids.
pub const DUMMY_NODE_ID: NodeId = NodeId::MAX; pub const DUMMY_NODE_ID: NodeId = NodeId::MAX;
/// A modifier on a bound, currently this is only used for `?Sized`, where the /// A modifier on a bound, e.g., `?Sized` or `?const Trait`.
/// modifier is `Maybe`. Negative bounds should also be handled here. ///
/// Negative bounds should also be handled here.
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)] #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
pub enum TraitBoundModifier { pub enum TraitBoundModifier {
/// No modifiers
None, None,
/// `?Trait`
Maybe, Maybe,
/// `?const Trait`
MaybeConst,
} }
/// The AST represents all type param bounds as types. /// The AST represents all type param bounds as types.