Skip to content

Commit 1c44857

Browse files
authored
Auto merge of rust-lang#37791 - petrochenkov:where, r=nikomatsakis
Support `?Sized` in where clauses Implemented as described in rust-lang#20503 (comment) - `?Trait` bounds are moved on type parameter definitions when possible, reported as errors otherwise. (It'd be nice to unify bounds and where clauses in HIR, but this is mostly blocked by rustdoc now - it needs to render bounds in pleasant way and the best way to do it so far is to mirror what was written in source code.) Fixes rust-lang#20503 r? @nikomatsakis
2 parents 39c267a + 7d15250 commit 1c44857

File tree

6 files changed

+161
-35
lines changed

6 files changed

+161
-35
lines changed

src/librustc/hir/lowering.rs

+59-7
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ use hir::map::definitions::DefPathData;
4646
use hir::def_id::{DefIndex, DefId};
4747
use hir::def::{Def, PathResolution};
4848
use session::Session;
49+
use util::nodemap::NodeMap;
4950

5051
use std::collections::BTreeMap;
5152
use std::iter;
@@ -508,7 +509,7 @@ impl<'a> LoweringContext<'a> {
508509
}
509510
}
510511

511-
fn lower_ty_param(&mut self, tp: &TyParam) -> hir::TyParam {
512+
fn lower_ty_param(&mut self, tp: &TyParam, add_bounds: &[TyParamBound]) -> hir::TyParam {
512513
let mut name = tp.ident.name;
513514

514515
// Don't expose `Self` (recovered "keyword used as ident" parse error).
@@ -518,18 +519,26 @@ impl<'a> LoweringContext<'a> {
518519
name = Symbol::gensym("Self");
519520
}
520521

522+
let mut bounds = self.lower_bounds(&tp.bounds);
523+
if !add_bounds.is_empty() {
524+
bounds = bounds.into_iter().chain(self.lower_bounds(add_bounds).into_iter()).collect();
525+
}
526+
521527
hir::TyParam {
522528
id: tp.id,
523529
name: name,
524-
bounds: self.lower_bounds(&tp.bounds),
530+
bounds: bounds,
525531
default: tp.default.as_ref().map(|x| self.lower_ty(x)),
526532
span: tp.span,
527533
pure_wrt_drop: tp.attrs.iter().any(|attr| attr.check_name("may_dangle")),
528534
}
529535
}
530536

531-
fn lower_ty_params(&mut self, tps: &P<[TyParam]>) -> hir::HirVec<hir::TyParam> {
532-
tps.iter().map(|tp| self.lower_ty_param(tp)).collect()
537+
fn lower_ty_params(&mut self, tps: &P<[TyParam]>, add_bounds: &NodeMap<Vec<TyParamBound>>)
538+
-> hir::HirVec<hir::TyParam> {
539+
tps.iter().map(|tp| {
540+
self.lower_ty_param(tp, add_bounds.get(&tp.id).map_or(&[][..], |x| &x))
541+
}).collect()
533542
}
534543

535544
fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
@@ -561,8 +570,47 @@ impl<'a> LoweringContext<'a> {
561570
}
562571

563572
fn lower_generics(&mut self, g: &Generics) -> hir::Generics {
573+
// Collect `?Trait` bounds in where clause and move them to parameter definitions.
574+
let mut add_bounds = NodeMap();
575+
for pred in &g.where_clause.predicates {
576+
if let WherePredicate::BoundPredicate(ref bound_pred) = *pred {
577+
'next_bound: for bound in &bound_pred.bounds {
578+
if let TraitTyParamBound(_, TraitBoundModifier::Maybe) = *bound {
579+
let report_error = |this: &mut Self| {
580+
this.diagnostic().span_err(bound_pred.bounded_ty.span,
581+
"`?Trait` bounds are only permitted at the \
582+
point where a type parameter is declared");
583+
};
584+
// Check if the where clause type is a plain type parameter.
585+
match bound_pred.bounded_ty.node {
586+
TyKind::Path(None, ref path)
587+
if !path.global && path.segments.len() == 1 &&
588+
bound_pred.bound_lifetimes.is_empty() => {
589+
if let Some(Def::TyParam(def_id)) =
590+
self.resolver.get_resolution(bound_pred.bounded_ty.id)
591+
.map(|d| d.base_def) {
592+
if let Some(node_id) =
593+
self.resolver.definitions().as_local_node_id(def_id) {
594+
for ty_param in &g.ty_params {
595+
if node_id == ty_param.id {
596+
add_bounds.entry(ty_param.id).or_insert(Vec::new())
597+
.push(bound.clone());
598+
continue 'next_bound;
599+
}
600+
}
601+
}
602+
}
603+
report_error(self)
604+
}
605+
_ => report_error(self)
606+
}
607+
}
608+
}
609+
}
610+
}
611+
564612
hir::Generics {
565-
ty_params: self.lower_ty_params(&g.ty_params),
613+
ty_params: self.lower_ty_params(&g.ty_params, &add_bounds),
566614
lifetimes: self.lower_lifetime_defs(&g.lifetimes),
567615
where_clause: self.lower_where_clause(&g.where_clause),
568616
span: g.span,
@@ -588,7 +636,11 @@ impl<'a> LoweringContext<'a> {
588636
hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
589637
bound_lifetimes: self.lower_lifetime_defs(bound_lifetimes),
590638
bounded_ty: self.lower_ty(bounded_ty),
591-
bounds: bounds.iter().map(|x| self.lower_ty_param_bound(x)).collect(),
639+
bounds: bounds.iter().filter_map(|bound| match *bound {
640+
// Ignore `?Trait` bounds, they were copied into type parameters already.
641+
TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
642+
_ => Some(self.lower_ty_param_bound(bound))
643+
}).collect(),
592644
span: span,
593645
})
594646
}
@@ -677,7 +729,7 @@ impl<'a> LoweringContext<'a> {
677729
}
678730
}
679731

680-
fn lower_bounds(&mut self, bounds: &TyParamBounds) -> hir::TyParamBounds {
732+
fn lower_bounds(&mut self, bounds: &[TyParamBound]) -> hir::TyParamBounds {
681733
bounds.iter().map(|bound| self.lower_ty_param_bound(bound)).collect()
682734
}
683735

src/librustc_passes/ast_validation.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,19 @@ impl<'a> AstValidator<'a> {
8686
_ => {}
8787
}
8888
}
89+
90+
fn no_questions_in_bounds(&self, bounds: &TyParamBounds, where_: &str, is_trait: bool) {
91+
for bound in bounds {
92+
if let TraitTyParamBound(ref poly, TraitBoundModifier::Maybe) = *bound {
93+
let mut err = self.err_handler().struct_span_err(poly.span,
94+
&format!("`?Trait` is not permitted in {}", where_));
95+
if is_trait {
96+
err.note(&format!("traits are `?{}` by default", poly.trait_ref.path));
97+
}
98+
err.emit();
99+
}
100+
}
101+
}
89102
}
90103

91104
impl<'a> Visitor for AstValidator<'a> {
@@ -130,6 +143,10 @@ impl<'a> Visitor for AstValidator<'a> {
130143
err.emit();
131144
});
132145
}
146+
TyKind::ObjectSum(_, ref bounds) |
147+
TyKind::PolyTraitRef(ref bounds) => {
148+
self.no_questions_in_bounds(bounds, "trait object types", false);
149+
}
133150
_ => {}
134151
}
135152

@@ -189,7 +206,8 @@ impl<'a> Visitor for AstValidator<'a> {
189206
}
190207
}
191208
}
192-
ItemKind::Trait(.., ref trait_items) => {
209+
ItemKind::Trait(.., ref bounds, ref trait_items) => {
210+
self.no_questions_in_bounds(bounds, "supertraits", true);
193211
for trait_item in trait_items {
194212
if let TraitItemKind::Method(ref sig, ref block) = trait_item.node {
195213
self.check_trait_fn_not_const(sig.constness);

src/libsyntax/parse/parser.rs

+10-27
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,6 @@ pub enum PathStyle {
8888
Expr,
8989
}
9090

91-
/// How to parse a bound, whether to allow bound modifiers such as `?`.
92-
#[derive(Copy, Clone, PartialEq)]
93-
pub enum BoundParsingMode {
94-
Bare,
95-
Modified,
96-
}
97-
9891
#[derive(Clone, Copy, PartialEq)]
9992
pub enum SemiColonMode {
10093
Break,
@@ -1041,7 +1034,7 @@ impl<'a> Parser<'a> {
10411034
trait_ref: trait_ref,
10421035
span: mk_sp(lo, hi)};
10431036
let other_bounds = if self.eat(&token::BinOp(token::Plus)) {
1044-
self.parse_ty_param_bounds(BoundParsingMode::Bare)?
1037+
self.parse_ty_param_bounds()?
10451038
} else {
10461039
P::new()
10471040
};
@@ -1059,7 +1052,7 @@ impl<'a> Parser<'a> {
10591052
The `impl` has already been consumed.
10601053
*/
10611054

1062-
let bounds = self.parse_ty_param_bounds(BoundParsingMode::Modified)?;
1055+
let bounds = self.parse_ty_param_bounds()?;
10631056

10641057
if !bounds.iter().any(|b| if let TraitTyParamBound(..) = *b { true } else { false }) {
10651058
self.span_err(self.prev_span, "at least one trait must be specified");
@@ -1271,7 +1264,7 @@ impl<'a> Parser<'a> {
12711264
return Ok(lhs);
12721265
}
12731266

1274-
let bounds = self.parse_ty_param_bounds(BoundParsingMode::Bare)?;
1267+
let bounds = self.parse_ty_param_bounds()?;
12751268

12761269
// In type grammar, `+` is treated like a binary operator,
12771270
// and hence both L and R side are required.
@@ -4148,24 +4141,20 @@ impl<'a> Parser<'a> {
41484141

41494142
// Parses a sequence of bounds if a `:` is found,
41504143
// otherwise returns empty list.
4151-
fn parse_colon_then_ty_param_bounds(&mut self,
4152-
mode: BoundParsingMode)
4153-
-> PResult<'a, TyParamBounds>
4144+
fn parse_colon_then_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds>
41544145
{
41554146
if !self.eat(&token::Colon) {
41564147
Ok(P::new())
41574148
} else {
4158-
self.parse_ty_param_bounds(mode)
4149+
self.parse_ty_param_bounds()
41594150
}
41604151
}
41614152

41624153
// matches bounds = ( boundseq )?
41634154
// where boundseq = ( polybound + boundseq ) | polybound
41644155
// and polybound = ( 'for' '<' 'region '>' )? bound
41654156
// and bound = 'region | trait_ref
4166-
fn parse_ty_param_bounds(&mut self,
4167-
mode: BoundParsingMode)
4168-
-> PResult<'a, TyParamBounds>
4157+
fn parse_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds>
41694158
{
41704159
let mut result = vec![];
41714160
loop {
@@ -4187,13 +4176,7 @@ impl<'a> Parser<'a> {
41874176
token::ModSep | token::Ident(..) => {
41884177
let poly_trait_ref = self.parse_poly_trait_ref()?;
41894178
let modifier = if ate_question {
4190-
if mode == BoundParsingMode::Modified {
4191-
TraitBoundModifier::Maybe
4192-
} else {
4193-
self.span_err(question_span,
4194-
"unexpected `?`");
4195-
TraitBoundModifier::None
4196-
}
4179+
TraitBoundModifier::Maybe
41974180
} else {
41984181
TraitBoundModifier::None
41994182
};
@@ -4215,7 +4198,7 @@ impl<'a> Parser<'a> {
42154198
let span = self.span;
42164199
let ident = self.parse_ident()?;
42174200

4218-
let bounds = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Modified)?;
4201+
let bounds = self.parse_colon_then_ty_param_bounds()?;
42194202

42204203
let default = if self.check(&token::Eq) {
42214204
self.bump();
@@ -4439,7 +4422,7 @@ impl<'a> Parser<'a> {
44394422
let bounded_ty = self.parse_ty()?;
44404423

44414424
if self.eat(&token::Colon) {
4442-
let bounds = self.parse_ty_param_bounds(BoundParsingMode::Bare)?;
4425+
let bounds = self.parse_ty_param_bounds()?;
44434426
let hi = self.prev_span.hi;
44444427
let span = mk_sp(lo, hi);
44454428

@@ -4901,7 +4884,7 @@ impl<'a> Parser<'a> {
49014884
let mut tps = self.parse_generics()?;
49024885

49034886
// Parse supertrait bounds.
4904-
let bounds = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare)?;
4887+
let bounds = self.parse_colon_then_ty_param_bounds()?;
49054888

49064889
tps.where_clause = self.parse_where_clause()?;
49074890

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(rustc_attrs)]
12+
13+
struct S<T>(*const T) where T: ?Sized;
14+
15+
#[rustc_error]
16+
fn main() { //~ ERROR compilation successful
17+
let u = vec![1, 2, 3];
18+
let _s: S<[u8]> = S(&u[..]);
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct S1<T>(T) where (T): ?Sized;
12+
//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared
13+
14+
struct S2<T>(T) where u8: ?Sized;
15+
//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared
16+
17+
struct S3<T>(T) where &'static T: ?Sized;
18+
//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared
19+
20+
trait Trait<'a> {}
21+
22+
struct S4<T>(T) where for<'a> T: ?Trait<'a>;
23+
//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared
24+
25+
struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
26+
//~^ ERROR type parameter has more than one relaxed default bound
27+
//~| WARN default bound relaxed for a type parameter
28+
29+
impl<T> S1<T> {
30+
fn f() where T: ?Sized {}
31+
//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared
32+
}
33+
34+
fn main() {
35+
let u = vec![1, 2, 3];
36+
let _s: S5<[u8]> = S5(&u[..]); // OK
37+
}

src/test/compile-fail/maybe-bounds.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
trait Tr: ?Sized {} //~ ERROR `?Trait` is not permitted in supertraits
12+
//~^ NOTE traits are `?Sized` by default
13+
14+
type A1 = Tr + ?Sized; //~ ERROR `?Trait` is not permitted in trait object types
15+
type A2 = for<'a> Tr + ?Sized; //~ ERROR `?Trait` is not permitted in trait object types
16+
17+
fn main() {}

0 commit comments

Comments
 (0)