Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

librustc: Allow trait bounds on structures and enumerations, and check #16432

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/liblibc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1456,13 +1456,24 @@ pub mod types {
pub Data4: [BYTE, ..8],
}

// NOTE(pcwalton, stage0): Remove after snapshot (typeck bug
// workaround).
#[cfg(stage0)]
pub struct WSAPROTOCOLCHAIN {
pub ChainLen: c_int,
pub ChainEntries: [DWORD, ..MAX_PROTOCOL_CHAIN],
}
#[cfg(not(stage0))]
pub struct WSAPROTOCOLCHAIN {
pub ChainLen: c_int,
pub ChainEntries: [DWORD, ..MAX_PROTOCOL_CHAIN as uint],
}

pub type LPWSAPROTOCOLCHAIN = *mut WSAPROTOCOLCHAIN;

// NOTE(pcwalton, stage0): Remove after snapshot (typeck bug
// workaround).
#[cfg(stage0)]
pub struct WSAPROTOCOL_INFO {
pub dwServiceFlags1: DWORD,
pub dwServiceFlags2: DWORD,
Expand All @@ -1485,6 +1496,29 @@ pub mod types {
pub dwProviderReserved: DWORD,
pub szProtocol: [u8, ..WSAPROTOCOL_LEN+1],
}
#[cfg(not(stage0))]
pub struct WSAPROTOCOL_INFO {
pub dwServiceFlags1: DWORD,
pub dwServiceFlags2: DWORD,
pub dwServiceFlags3: DWORD,
pub dwServiceFlags4: DWORD,
pub dwProviderFlags: DWORD,
pub ProviderId: GUID,
pub dwCatalogEntryId: DWORD,
pub ProtocolChain: WSAPROTOCOLCHAIN,
pub iVersion: c_int,
pub iAddressFamily: c_int,
pub iMaxSockAddr: c_int,
pub iMinSockAddr: c_int,
pub iSocketType: c_int,
pub iProtocol: c_int,
pub iProtocolMaxOffset: c_int,
pub iNetworkByteOrder: c_int,
pub iSecurityScheme: c_int,
pub dwMessageSize: DWORD,
pub dwProviderReserved: DWORD,
pub szProtocol: [u8, ..(WSAPROTOCOL_LEN as uint) + 1u],
}

pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;

Expand Down
12 changes: 12 additions & 0 deletions src/librustc/middle/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use middle::def;
use middle::pat_util::def_to_path;
use middle::ty;
use middle::typeck::astconv;
use middle::typeck::check;
use util::nodemap::{DefIdMap};

use syntax::ast::*;
Expand Down Expand Up @@ -274,6 +275,17 @@ impl<'a> ConstEvalVisitor<'a> {
}

impl<'a> Visitor<()> for ConstEvalVisitor<'a> {
fn visit_ty(&mut self, t: &Ty, _: ()) {
match t.node {
TyFixedLengthVec(_, expr) => {
check::check_const_in_type(self.tcx, &*expr, ty::mk_uint());
}
_ => {}
}

visit::walk_ty(self, t, ());
}

fn visit_expr_post(&mut self, e: &Expr, _: ()) {
self.classify(e);
}
Expand Down
198 changes: 191 additions & 7 deletions src/librustc/middle/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,24 @@
use middle::freevars::freevar_entry;
use middle::freevars;
use middle::subst;
use middle::ty::ParameterEnvironment;
use middle::ty;
use middle::ty_fold;
use middle::ty_fold::TypeFoldable;
use middle::typeck;
use middle::ty_fold;
use middle::typeck::check::vtable;
use middle::typeck::{MethodCall, NoAdjustment};
use middle::typeck;
use util::ppaux::{Repr, ty_to_string};
use util::ppaux::UserString;

use std::collections::HashSet;
use syntax::ast::*;
use syntax::ast_util;
use syntax::attr;
use syntax::codemap::Span;
use syntax::print::pprust::{expr_to_string, ident_to_string};
use syntax::{visit};
use syntax::visit::Visitor;
use syntax::visit;

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

#[deriving(Clone)]
pub struct Context<'a> {
tcx: &'a ty::ctxt,
struct_and_enum_bounds_checked: HashSet<ty::t>,
parameter_environments: Vec<ParameterEnvironment>,
}

impl<'a> Visitor<()> for Context<'a> {

fn visit_expr(&mut self, ex: &Expr, _: ()) {
check_expr(self, ex);
}
Expand All @@ -74,12 +78,18 @@ impl<'a> Visitor<()> for Context<'a> {
fn visit_pat(&mut self, p: &Pat, _: ()) {
check_pat(self, p);
}

fn visit_local(&mut self, l: &Local, _: ()) {
check_local(self, l);
}
}

pub fn check_crate(tcx: &ty::ctxt,
krate: &Crate) {
let mut ctx = Context {
tcx: tcx,
struct_and_enum_bounds_checked: HashSet::new(),
parameter_environments: Vec::new(),
};
visit::walk_crate(&mut ctx, krate, ());
tcx.sess.abort_if_errors();
Expand Down Expand Up @@ -165,12 +175,90 @@ fn check_item(cx: &mut Context, item: &Item) {
match item.node {
ItemImpl(_, Some(ref trait_ref), ref self_type, _) => {
check_impl_of_trait(cx, item, trait_ref, &**self_type);

let parameter_environment =
ParameterEnvironment::for_item(cx.tcx, item.id);
cx.parameter_environments.push(parameter_environment);

// Check bounds on the `self` type.
check_bounds_on_structs_or_enums_in_type_if_possible(
cx,
item.span,
ty::node_id_to_type(cx.tcx, item.id));

// Check bounds on the trait ref.
match ty::impl_trait_ref(cx.tcx,
ast_util::local_def(item.id)) {
None => {}
Some(trait_ref) => {
check_bounds_on_structs_or_enums_in_trait_ref(
cx,
item.span,
&*trait_ref);
}
}

drop(cx.parameter_environments.pop());
}
ItemEnum(..) => {
let parameter_environment =
ParameterEnvironment::for_item(cx.tcx, item.id);
cx.parameter_environments.push(parameter_environment);

let def_id = ast_util::local_def(item.id);
for variant in ty::enum_variants(cx.tcx, def_id).iter() {
for arg in variant.args.iter() {
check_bounds_on_structs_or_enums_in_type_if_possible(
cx,
item.span,
*arg)
}
}

drop(cx.parameter_environments.pop());
}
ItemStruct(..) => {
let parameter_environment =
ParameterEnvironment::for_item(cx.tcx, item.id);
cx.parameter_environments.push(parameter_environment);

let def_id = ast_util::local_def(item.id);
for field in ty::lookup_struct_fields(cx.tcx, def_id).iter() {
check_bounds_on_structs_or_enums_in_type_if_possible(
cx,
item.span,
ty::node_id_to_type(cx.tcx, field.id.node))
}

drop(cx.parameter_environments.pop());

}
ItemStatic(..) => {
let parameter_environment =
ParameterEnvironment::for_item(cx.tcx, item.id);
cx.parameter_environments.push(parameter_environment);

check_bounds_on_structs_or_enums_in_type_if_possible(
cx,
item.span,
ty::node_id_to_type(cx.tcx, item.id));

drop(cx.parameter_environments.pop());
}
_ => {}
}
}

visit::walk_item(cx, item, ());
visit::walk_item(cx, item, ())
}

fn check_local(cx: &mut Context, local: &Local) {
check_bounds_on_structs_or_enums_in_type_if_possible(
cx,
local.span,
ty::node_id_to_type(cx.tcx, local.id));

visit::walk_local(cx, local, ())
}

// Yields the appropriate function to check the kind of closed over
Expand Down Expand Up @@ -254,7 +342,25 @@ fn check_fn(
});
});

visit::walk_fn(cx, fk, decl, body, sp, ());
match *fk {
visit::FkFnBlock(..) => {
let ty = ty::node_id_to_type(cx.tcx, fn_id);
check_bounds_on_structs_or_enums_in_type_if_possible(cx, sp, ty);

visit::walk_fn(cx, fk, decl, body, sp, ())
}
visit::FkItemFn(..) | visit::FkMethod(..) => {
let parameter_environment = ParameterEnvironment::for_item(cx.tcx,
fn_id);
cx.parameter_environments.push(parameter_environment);

let ty = ty::node_id_to_type(cx.tcx, fn_id);
check_bounds_on_structs_or_enums_in_type_if_possible(cx, sp, ty);

visit::walk_fn(cx, fk, decl, body, sp, ());
drop(cx.parameter_environments.pop());
}
}
}

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

// Check bounds on structures or enumerations in the type of the
// expression.
let expression_type = ty::expr_ty(cx.tcx, e);
check_bounds_on_structs_or_enums_in_type_if_possible(cx,
e.span,
expression_type);

match e.node {
ExprBox(ref loc, ref interior) => {
let def = ty::resolve_expr(cx.tcx, &**loc);
Expand Down Expand Up @@ -483,6 +596,7 @@ fn check_ty(cx: &mut Context, aty: &Ty) {
}
_ => {}
}

visit::walk_ty(cx, aty, ());
}

Expand Down Expand Up @@ -519,6 +633,76 @@ pub fn check_typaram_bounds(cx: &Context,
});
}

fn check_bounds_on_structs_or_enums_in_type_if_possible(cx: &mut Context,
span: Span,
ty: ty::t) {
// If we aren't in a function, structure, or enumeration context, we don't
// have enough information to ensure that bounds on structures or
// enumerations are satisfied. So we don't perform the check.
if cx.parameter_environments.len() == 0 {
return
}

// If we've already checked for this type, don't do it again. This
// massively speeds up kind checking.
if cx.struct_and_enum_bounds_checked.contains(&ty) {
return
}
cx.struct_and_enum_bounds_checked.insert(ty);

ty::walk_ty(ty, |ty| {
match ty::get(ty).sty {
ty::ty_struct(type_id, ref substs) |
ty::ty_enum(type_id, ref substs) => {
let polytype = ty::lookup_item_type(cx.tcx, type_id);

// Check builtin bounds.
for (ty, type_param_def) in substs.types
.iter()
.zip(polytype.generics
.types
.iter()) {
check_typaram_bounds(cx, span, *ty, type_param_def)
}

// Check trait bounds.
let parameter_environment =
cx.parameter_environments.get(cx.parameter_environments
.len() - 1);
debug!(
"check_bounds_on_structs_or_enums_in_type_if_possible(): \
checking {}",
ty.repr(cx.tcx));
vtable::check_param_bounds(cx.tcx,
span,
parameter_environment,
&polytype.generics.types,
substs,
|missing| {
cx.tcx
.sess
.span_err(span,
format!("instantiating a type parameter with \
an incompatible type `{}`, which \
does not fulfill `{}`",
ty_to_string(cx.tcx, ty),
missing.user_string(
cx.tcx)).as_slice());
})
}
_ => {}
}
});
}

fn check_bounds_on_structs_or_enums_in_trait_ref(cx: &mut Context,
span: Span,
trait_ref: &ty::TraitRef) {
for ty in trait_ref.substs.types.iter() {
check_bounds_on_structs_or_enums_in_type_if_possible(cx, span, *ty)
}
}

pub fn check_freevar_bounds(cx: &Context, sp: Span, ty: ty::t,
bounds: ty::BuiltinBounds, referenced_ty: Option<ty::t>)
{
Expand Down
Loading