Skip to content

Commit 086a5ca

Browse files
committed
librustc: Allow trait bounds on structures and enumerations, and check
them during kind checking. This implements RFC #11. Closes #15759.
1 parent cb9c1e0 commit 086a5ca

26 files changed

+622
-43
lines changed

src/liblibc/lib.rs

+34
Original file line numberDiff line numberDiff line change
@@ -1456,13 +1456,24 @@ pub mod types {
14561456
pub Data4: [BYTE, ..8],
14571457
}
14581458

1459+
// NOTE(pcwalton, stage0): Remove after snapshot (typeck bug
1460+
// workaround).
1461+
#[cfg(stage0)]
14591462
pub struct WSAPROTOCOLCHAIN {
14601463
pub ChainLen: c_int,
14611464
pub ChainEntries: [DWORD, ..MAX_PROTOCOL_CHAIN],
14621465
}
1466+
#[cfg(not(stage0))]
1467+
pub struct WSAPROTOCOLCHAIN {
1468+
pub ChainLen: c_int,
1469+
pub ChainEntries: [DWORD, ..MAX_PROTOCOL_CHAIN as uint],
1470+
}
14631471

14641472
pub type LPWSAPROTOCOLCHAIN = *mut WSAPROTOCOLCHAIN;
14651473

1474+
// NOTE(pcwalton, stage0): Remove after snapshot (typeck bug
1475+
// workaround).
1476+
#[cfg(stage0)]
14661477
pub struct WSAPROTOCOL_INFO {
14671478
pub dwServiceFlags1: DWORD,
14681479
pub dwServiceFlags2: DWORD,
@@ -1485,6 +1496,29 @@ pub mod types {
14851496
pub dwProviderReserved: DWORD,
14861497
pub szProtocol: [u8, ..WSAPROTOCOL_LEN+1],
14871498
}
1499+
#[cfg(not(stage0))]
1500+
pub struct WSAPROTOCOL_INFO {
1501+
pub dwServiceFlags1: DWORD,
1502+
pub dwServiceFlags2: DWORD,
1503+
pub dwServiceFlags3: DWORD,
1504+
pub dwServiceFlags4: DWORD,
1505+
pub dwProviderFlags: DWORD,
1506+
pub ProviderId: GUID,
1507+
pub dwCatalogEntryId: DWORD,
1508+
pub ProtocolChain: WSAPROTOCOLCHAIN,
1509+
pub iVersion: c_int,
1510+
pub iAddressFamily: c_int,
1511+
pub iMaxSockAddr: c_int,
1512+
pub iMinSockAddr: c_int,
1513+
pub iSocketType: c_int,
1514+
pub iProtocol: c_int,
1515+
pub iProtocolMaxOffset: c_int,
1516+
pub iNetworkByteOrder: c_int,
1517+
pub iSecurityScheme: c_int,
1518+
pub dwMessageSize: DWORD,
1519+
pub dwProviderReserved: DWORD,
1520+
pub szProtocol: [u8, ..(WSAPROTOCOL_LEN as uint) + 1u],
1521+
}
14881522

14891523
pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;
14901524

src/librustc/middle/const_eval.rs

+12
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use middle::def;
1717
use middle::pat_util::def_to_path;
1818
use middle::ty;
1919
use middle::typeck::astconv;
20+
use middle::typeck::check;
2021
use util::nodemap::{DefIdMap};
2122

2223
use syntax::ast::*;
@@ -274,6 +275,17 @@ impl<'a> ConstEvalVisitor<'a> {
274275
}
275276

276277
impl<'a> Visitor<()> for ConstEvalVisitor<'a> {
278+
fn visit_ty(&mut self, t: &Ty, _: ()) {
279+
match t.node {
280+
TyFixedLengthVec(_, expr) => {
281+
check::check_const_in_type(self.tcx, &*expr, ty::mk_uint());
282+
}
283+
_ => {}
284+
}
285+
286+
visit::walk_ty(self, t, ());
287+
}
288+
277289
fn visit_expr_post(&mut self, e: &Expr, _: ()) {
278290
self.classify(e);
279291
}

src/librustc/middle/kind.rs

+191-7
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,24 @@
1212
use middle::freevars::freevar_entry;
1313
use middle::freevars;
1414
use middle::subst;
15+
use middle::ty::ParameterEnvironment;
1516
use middle::ty;
16-
use middle::ty_fold;
1717
use middle::ty_fold::TypeFoldable;
18-
use middle::typeck;
18+
use middle::ty_fold;
19+
use middle::typeck::check::vtable;
1920
use middle::typeck::{MethodCall, NoAdjustment};
21+
use middle::typeck;
2022
use util::ppaux::{Repr, ty_to_string};
2123
use util::ppaux::UserString;
2224

25+
use std::collections::HashSet;
2326
use syntax::ast::*;
27+
use syntax::ast_util;
2428
use syntax::attr;
2529
use syntax::codemap::Span;
2630
use syntax::print::pprust::{expr_to_string, ident_to_string};
27-
use syntax::{visit};
2831
use syntax::visit::Visitor;
32+
use syntax::visit;
2933

3034
// Kind analysis pass.
3135
//
@@ -47,13 +51,13 @@ use syntax::visit::Visitor;
4751
// primitives in the stdlib are explicitly annotated to only take sendable
4852
// types.
4953

50-
#[deriving(Clone)]
5154
pub struct Context<'a> {
5255
tcx: &'a ty::ctxt,
56+
struct_and_enum_bounds_checked: HashSet<ty::t>,
57+
parameter_environments: Vec<ParameterEnvironment>,
5358
}
5459

5560
impl<'a> Visitor<()> for Context<'a> {
56-
5761
fn visit_expr(&mut self, ex: &Expr, _: ()) {
5862
check_expr(self, ex);
5963
}
@@ -74,12 +78,18 @@ impl<'a> Visitor<()> for Context<'a> {
7478
fn visit_pat(&mut self, p: &Pat, _: ()) {
7579
check_pat(self, p);
7680
}
81+
82+
fn visit_local(&mut self, l: &Local, _: ()) {
83+
check_local(self, l);
84+
}
7785
}
7886

7987
pub fn check_crate(tcx: &ty::ctxt,
8088
krate: &Crate) {
8189
let mut ctx = Context {
8290
tcx: tcx,
91+
struct_and_enum_bounds_checked: HashSet::new(),
92+
parameter_environments: Vec::new(),
8393
};
8494
visit::walk_crate(&mut ctx, krate, ());
8595
tcx.sess.abort_if_errors();
@@ -165,12 +175,90 @@ fn check_item(cx: &mut Context, item: &Item) {
165175
match item.node {
166176
ItemImpl(_, Some(ref trait_ref), ref self_type, _) => {
167177
check_impl_of_trait(cx, item, trait_ref, &**self_type);
178+
179+
let parameter_environment =
180+
ParameterEnvironment::for_item(cx.tcx, item.id);
181+
cx.parameter_environments.push(parameter_environment);
182+
183+
// Check bounds on the `self` type.
184+
check_bounds_on_structs_or_enums_in_type_if_possible(
185+
cx,
186+
item.span,
187+
ty::node_id_to_type(cx.tcx, item.id));
188+
189+
// Check bounds on the trait ref.
190+
match ty::impl_trait_ref(cx.tcx,
191+
ast_util::local_def(item.id)) {
192+
None => {}
193+
Some(trait_ref) => {
194+
check_bounds_on_structs_or_enums_in_trait_ref(
195+
cx,
196+
item.span,
197+
&*trait_ref);
198+
}
199+
}
200+
201+
drop(cx.parameter_environments.pop());
202+
}
203+
ItemEnum(..) => {
204+
let parameter_environment =
205+
ParameterEnvironment::for_item(cx.tcx, item.id);
206+
cx.parameter_environments.push(parameter_environment);
207+
208+
let def_id = ast_util::local_def(item.id);
209+
for variant in ty::enum_variants(cx.tcx, def_id).iter() {
210+
for arg in variant.args.iter() {
211+
check_bounds_on_structs_or_enums_in_type_if_possible(
212+
cx,
213+
item.span,
214+
*arg)
215+
}
216+
}
217+
218+
drop(cx.parameter_environments.pop());
219+
}
220+
ItemStruct(..) => {
221+
let parameter_environment =
222+
ParameterEnvironment::for_item(cx.tcx, item.id);
223+
cx.parameter_environments.push(parameter_environment);
224+
225+
let def_id = ast_util::local_def(item.id);
226+
for field in ty::lookup_struct_fields(cx.tcx, def_id).iter() {
227+
check_bounds_on_structs_or_enums_in_type_if_possible(
228+
cx,
229+
item.span,
230+
ty::node_id_to_type(cx.tcx, field.id.node))
231+
}
232+
233+
drop(cx.parameter_environments.pop());
234+
235+
}
236+
ItemStatic(..) => {
237+
let parameter_environment =
238+
ParameterEnvironment::for_item(cx.tcx, item.id);
239+
cx.parameter_environments.push(parameter_environment);
240+
241+
check_bounds_on_structs_or_enums_in_type_if_possible(
242+
cx,
243+
item.span,
244+
ty::node_id_to_type(cx.tcx, item.id));
245+
246+
drop(cx.parameter_environments.pop());
168247
}
169248
_ => {}
170249
}
171250
}
172251

173-
visit::walk_item(cx, item, ());
252+
visit::walk_item(cx, item, ())
253+
}
254+
255+
fn check_local(cx: &mut Context, local: &Local) {
256+
check_bounds_on_structs_or_enums_in_type_if_possible(
257+
cx,
258+
local.span,
259+
ty::node_id_to_type(cx.tcx, local.id));
260+
261+
visit::walk_local(cx, local, ())
174262
}
175263

176264
// Yields the appropriate function to check the kind of closed over
@@ -254,7 +342,25 @@ fn check_fn(
254342
});
255343
});
256344

257-
visit::walk_fn(cx, fk, decl, body, sp, ());
345+
match *fk {
346+
visit::FkFnBlock(..) => {
347+
let ty = ty::node_id_to_type(cx.tcx, fn_id);
348+
check_bounds_on_structs_or_enums_in_type_if_possible(cx, sp, ty);
349+
350+
visit::walk_fn(cx, fk, decl, body, sp, ())
351+
}
352+
visit::FkItemFn(..) | visit::FkMethod(..) => {
353+
let parameter_environment = ParameterEnvironment::for_item(cx.tcx,
354+
fn_id);
355+
cx.parameter_environments.push(parameter_environment);
356+
357+
let ty = ty::node_id_to_type(cx.tcx, fn_id);
358+
check_bounds_on_structs_or_enums_in_type_if_possible(cx, sp, ty);
359+
360+
visit::walk_fn(cx, fk, decl, body, sp, ());
361+
drop(cx.parameter_environments.pop());
362+
}
363+
}
258364
}
259365

260366
pub fn check_expr(cx: &mut Context, e: &Expr) {
@@ -263,6 +369,13 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
263369
// Handle any kind bounds on type parameters
264370
check_bounds_on_type_parameters(cx, e);
265371

372+
// Check bounds on structures or enumerations in the type of the
373+
// expression.
374+
let expression_type = ty::expr_ty(cx.tcx, e);
375+
check_bounds_on_structs_or_enums_in_type_if_possible(cx,
376+
e.span,
377+
expression_type);
378+
266379
match e.node {
267380
ExprBox(ref loc, ref interior) => {
268381
let def = ty::resolve_expr(cx.tcx, &**loc);
@@ -483,6 +596,7 @@ fn check_ty(cx: &mut Context, aty: &Ty) {
483596
}
484597
_ => {}
485598
}
599+
486600
visit::walk_ty(cx, aty, ());
487601
}
488602

@@ -519,6 +633,76 @@ pub fn check_typaram_bounds(cx: &Context,
519633
});
520634
}
521635

636+
fn check_bounds_on_structs_or_enums_in_type_if_possible(cx: &mut Context,
637+
span: Span,
638+
ty: ty::t) {
639+
// If we aren't in a function, structure, or enumeration context, we don't
640+
// have enough information to ensure that bounds on structures or
641+
// enumerations are satisfied. So we don't perform the check.
642+
if cx.parameter_environments.len() == 0 {
643+
return
644+
}
645+
646+
// If we've already checked for this type, don't do it again. This
647+
// massively speeds up kind checking.
648+
if cx.struct_and_enum_bounds_checked.contains(&ty) {
649+
return
650+
}
651+
cx.struct_and_enum_bounds_checked.insert(ty);
652+
653+
ty::walk_ty(ty, |ty| {
654+
match ty::get(ty).sty {
655+
ty::ty_struct(type_id, ref substs) |
656+
ty::ty_enum(type_id, ref substs) => {
657+
let polytype = ty::lookup_item_type(cx.tcx, type_id);
658+
659+
// Check builtin bounds.
660+
for (ty, type_param_def) in substs.types
661+
.iter()
662+
.zip(polytype.generics
663+
.types
664+
.iter()) {
665+
check_typaram_bounds(cx, span, *ty, type_param_def)
666+
}
667+
668+
// Check trait bounds.
669+
let parameter_environment =
670+
cx.parameter_environments.get(cx.parameter_environments
671+
.len() - 1);
672+
debug!(
673+
"check_bounds_on_structs_or_enums_in_type_if_possible(): \
674+
checking {}",
675+
ty.repr(cx.tcx));
676+
vtable::check_param_bounds(cx.tcx,
677+
span,
678+
parameter_environment,
679+
&polytype.generics.types,
680+
substs,
681+
|missing| {
682+
cx.tcx
683+
.sess
684+
.span_err(span,
685+
format!("instantiating a type parameter with \
686+
an incompatible type `{}`, which \
687+
does not fulfill `{}`",
688+
ty_to_string(cx.tcx, ty),
689+
missing.user_string(
690+
cx.tcx)).as_slice());
691+
})
692+
}
693+
_ => {}
694+
}
695+
});
696+
}
697+
698+
fn check_bounds_on_structs_or_enums_in_trait_ref(cx: &mut Context,
699+
span: Span,
700+
trait_ref: &ty::TraitRef) {
701+
for ty in trait_ref.substs.types.iter() {
702+
check_bounds_on_structs_or_enums_in_type_if_possible(cx, span, *ty)
703+
}
704+
}
705+
522706
pub fn check_freevar_bounds(cx: &Context, sp: Span, ty: ty::t,
523707
bounds: ty::BuiltinBounds, referenced_ty: Option<ty::t>)
524708
{

0 commit comments

Comments
 (0)