Skip to content

Commit 7d15250

Browse files
committed
Support ?Sized in where clauses
1 parent a31ad75 commit 7d15250

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;
@@ -394,7 +395,7 @@ impl<'a> LoweringContext<'a> {
394395
}
395396
}
396397

397-
fn lower_ty_param(&mut self, tp: &TyParam) -> hir::TyParam {
398+
fn lower_ty_param(&mut self, tp: &TyParam, add_bounds: &[TyParamBound]) -> hir::TyParam {
398399
let mut name = tp.ident.name;
399400

400401
// Don't expose `Self` (recovered "keyword used as ident" parse error).
@@ -404,18 +405,26 @@ impl<'a> LoweringContext<'a> {
404405
name = Symbol::gensym("Self");
405406
}
406407

408+
let mut bounds = self.lower_bounds(&tp.bounds);
409+
if !add_bounds.is_empty() {
410+
bounds = bounds.into_iter().chain(self.lower_bounds(add_bounds).into_iter()).collect();
411+
}
412+
407413
hir::TyParam {
408414
id: tp.id,
409415
name: name,
410-
bounds: self.lower_bounds(&tp.bounds),
416+
bounds: bounds,
411417
default: tp.default.as_ref().map(|x| self.lower_ty(x)),
412418
span: tp.span,
413419
pure_wrt_drop: tp.attrs.iter().any(|attr| attr.check_name("may_dangle")),
414420
}
415421
}
416422

417-
fn lower_ty_params(&mut self, tps: &P<[TyParam]>) -> hir::HirVec<hir::TyParam> {
418-
tps.iter().map(|tp| self.lower_ty_param(tp)).collect()
423+
fn lower_ty_params(&mut self, tps: &P<[TyParam]>, add_bounds: &NodeMap<Vec<TyParamBound>>)
424+
-> hir::HirVec<hir::TyParam> {
425+
tps.iter().map(|tp| {
426+
self.lower_ty_param(tp, add_bounds.get(&tp.id).map_or(&[][..], |x| &x))
427+
}).collect()
419428
}
420429

421430
fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
@@ -447,8 +456,47 @@ impl<'a> LoweringContext<'a> {
447456
}
448457

449458
fn lower_generics(&mut self, g: &Generics) -> hir::Generics {
459+
// Collect `?Trait` bounds in where clause and move them to parameter definitions.
460+
let mut add_bounds = NodeMap();
461+
for pred in &g.where_clause.predicates {
462+
if let WherePredicate::BoundPredicate(ref bound_pred) = *pred {
463+
'next_bound: for bound in &bound_pred.bounds {
464+
if let TraitTyParamBound(_, TraitBoundModifier::Maybe) = *bound {
465+
let report_error = |this: &mut Self| {
466+
this.diagnostic().span_err(bound_pred.bounded_ty.span,
467+
"`?Trait` bounds are only permitted at the \
468+
point where a type parameter is declared");
469+
};
470+
// Check if the where clause type is a plain type parameter.
471+
match bound_pred.bounded_ty.node {
472+
TyKind::Path(None, ref path)
473+
if !path.global && path.segments.len() == 1 &&
474+
bound_pred.bound_lifetimes.is_empty() => {
475+
if let Some(Def::TyParam(def_id)) =
476+
self.resolver.get_resolution(bound_pred.bounded_ty.id)
477+
.map(|d| d.base_def) {
478+
if let Some(node_id) =
479+
self.resolver.definitions().as_local_node_id(def_id) {
480+
for ty_param in &g.ty_params {
481+
if node_id == ty_param.id {
482+
add_bounds.entry(ty_param.id).or_insert(Vec::new())
483+
.push(bound.clone());
484+
continue 'next_bound;
485+
}
486+
}
487+
}
488+
}
489+
report_error(self)
490+
}
491+
_ => report_error(self)
492+
}
493+
}
494+
}
495+
}
496+
}
497+
450498
hir::Generics {
451-
ty_params: self.lower_ty_params(&g.ty_params),
499+
ty_params: self.lower_ty_params(&g.ty_params, &add_bounds),
452500
lifetimes: self.lower_lifetime_defs(&g.lifetimes),
453501
where_clause: self.lower_where_clause(&g.where_clause),
454502
span: g.span,
@@ -474,7 +522,11 @@ impl<'a> LoweringContext<'a> {
474522
hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
475523
bound_lifetimes: self.lower_lifetime_defs(bound_lifetimes),
476524
bounded_ty: self.lower_ty(bounded_ty),
477-
bounds: bounds.iter().map(|x| self.lower_ty_param_bound(x)).collect(),
525+
bounds: bounds.iter().filter_map(|bound| match *bound {
526+
// Ignore `?Trait` bounds, they were copied into type parameters already.
527+
TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
528+
_ => Some(self.lower_ty_param_bound(bound))
529+
}).collect(),
478530
span: span,
479531
})
480532
}
@@ -563,7 +615,7 @@ impl<'a> LoweringContext<'a> {
563615
}
564616
}
565617

566-
fn lower_bounds(&mut self, bounds: &TyParamBounds) -> hir::TyParamBounds {
618+
fn lower_bounds(&mut self, bounds: &[TyParamBound]) -> hir::TyParamBounds {
567619
bounds.iter().map(|bound| self.lower_ty_param_bound(bound)).collect()
568620
}
569621

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)