Skip to content

Commit

Permalink
Integrate builtin bounds fully into the trait checker
Browse files Browse the repository at this point in the history
  • Loading branch information
nikomatsakis committed Sep 25, 2014
1 parent d299baf commit effb363
Show file tree
Hide file tree
Showing 28 changed files with 821 additions and 404 deletions.
8 changes: 4 additions & 4 deletions src/libcore/kinds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,19 @@ pub use self::Sync as Share;

/// Types able to be transferred across task boundaries.
#[lang="send"]
pub trait Send {
pub trait Send for Sized? {
// empty.
}

/// Types with a constant size known at compile-time.
#[lang="sized"]
pub trait Sized {
pub trait Sized for Sized? {
// Empty.
}

/// Types that can be copied by simply copying bits (i.e. `memcpy`).
#[lang="copy"]
pub trait Copy {
pub trait Copy for Sized? {
// Empty.
}

Expand Down Expand Up @@ -87,7 +87,7 @@ pub trait Copy {
/// reference; not doing this is undefined behaviour (for example,
/// `transmute`-ing from `&T` to `&mut T` is illegal).
#[lang="sync"]
pub trait Sync {
pub trait Sync for Sized? {
// Empty
}

Expand Down
4 changes: 1 addition & 3 deletions src/librustc/middle/traits/coherence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ use middle::ty;
use middle::typeck::infer::InferCtxt;
use syntax::ast;
use syntax::codemap::DUMMY_SP;
use util::nodemap::DefIdMap;
use util::ppaux::Repr;

pub fn impl_can_satisfy(infcx: &InferCtxt,
Expand All @@ -40,8 +39,7 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
// Determine whether `impl2` can provide an implementation for those
// same types.
let param_env = ty::empty_parameter_environment();
let unboxed_closures = DefIdMap::new();
match evaluate_impl(infcx, &param_env, &unboxed_closures, DUMMY_CAUSE,
match evaluate_impl(infcx, &param_env, infcx.tcx, DUMMY_CAUSE,
impl2_def_id, impl1_self_ty) {
EvaluatedToMatch | EvaluatedToAmbiguity => true,
EvaluatedToUnmatch => false,
Expand Down
133 changes: 15 additions & 118 deletions src/librustc/middle/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use middle::mem_categorization::Typer;
use middle::ty;
use middle::typeck::infer::{InferCtxt, skolemize};
use util::nodemap::DefIdMap;
use middle::typeck::infer::InferCtxt;
use util::ppaux::Repr;

use super::CodeAmbiguity;
use super::Obligation;
use super::FulfillmentError;
use super::CodeSelectionError;
use super::select::SelectionContext;
use super::Unimplemented;

/**
* The fulfillment context is used to drive trait resolution. It
Expand All @@ -36,17 +35,12 @@ pub struct FulfillmentContext {
// A list of all obligations that have been registered with this
// fulfillment context.
trait_obligations: Vec<Obligation>,

// For semi-hacky reasons (see FIXME below) we keep the builtin
// trait obligations segregated.
builtin_obligations: Vec<Obligation>,
}

impl FulfillmentContext {
pub fn new() -> FulfillmentContext {
FulfillmentContext {
trait_obligations: Vec::new(),
builtin_obligations: Vec::new()
}
}

Expand All @@ -55,24 +49,16 @@ impl FulfillmentContext {
obligation: Obligation)
{
debug!("register_obligation({})", obligation.repr(tcx));
match tcx.lang_items.to_builtin_kind(obligation.trait_ref.def_id) {
Some(_) => {
self.builtin_obligations.push(obligation);
}
None => {
self.trait_obligations.push(obligation);
}
}
self.trait_obligations.push(obligation);
}

pub fn select_all_or_error(&mut self,
infcx: &InferCtxt,
param_env: &ty::ParameterEnvironment,
unboxed_closures: &DefIdMap<ty::UnboxedClosure>)
-> Result<(),Vec<FulfillmentError>>
pub fn select_all_or_error<'a,'tcx>(&mut self,
infcx: &InferCtxt<'a,'tcx>,
param_env: &ty::ParameterEnvironment,
typer: &Typer<'tcx>)
-> Result<(),Vec<FulfillmentError>>
{
try!(self.select_where_possible(infcx, param_env,
unboxed_closures));
try!(self.select_where_possible(infcx, param_env, typer));

// Anything left is ambiguous.
let errors: Vec<FulfillmentError> =
Expand All @@ -88,15 +74,14 @@ impl FulfillmentContext {
}
}

pub fn select_where_possible(&mut self,
infcx: &InferCtxt,
param_env: &ty::ParameterEnvironment,
unboxed_closures: &DefIdMap<ty::UnboxedClosure>)
-> Result<(),Vec<FulfillmentError>>
pub fn select_where_possible<'a,'tcx>(&mut self,
infcx: &InferCtxt<'a,'tcx>,
param_env: &ty::ParameterEnvironment,
typer: &Typer<'tcx>)
-> Result<(),Vec<FulfillmentError>>
{
let tcx = infcx.tcx;
let selcx = SelectionContext::new(infcx, param_env,
unboxed_closures);
let mut selcx = SelectionContext::new(infcx, param_env, typer);

debug!("select_where_possible({} obligations) start",
self.trait_obligations.len());
Expand Down Expand Up @@ -158,92 +143,4 @@ impl FulfillmentContext {
Err(errors)
}
}

pub fn check_builtin_bound_obligations(
&self,
infcx: &InferCtxt)
-> Result<(),Vec<FulfillmentError>>
{
let tcx = infcx.tcx;
let mut errors = Vec::new();
debug!("check_builtin_bound_obligations");
for obligation in self.builtin_obligations.iter() {
debug!("obligation={}", obligation.repr(tcx));

let def_id = obligation.trait_ref.def_id;
let bound = match tcx.lang_items.to_builtin_kind(def_id) {
Some(bound) => { bound }
None => { continue; }
};

let unskol_self_ty = obligation.self_ty();

// Skolemize the self-type so that it no longer contains
// inference variables. Note that this also replaces
// regions with 'static. You might think that this is not
// ok, because checking whether something is `Send`
// implies checking whether it is 'static: that's true,
// but in fact the region bound is fed into region
// inference separately and enforced there (and that has
// even already been done before this code executes,
// generally speaking).
let self_ty = skolemize(infcx, unskol_self_ty);

debug!("bound={} self_ty={}", bound, self_ty.repr(tcx));
if ty::type_is_error(self_ty) {
// Indicates an error that was/will-be
// reported elsewhere.
continue;
}

// Determine if builtin bound is met.
let tc = ty::type_contents(tcx, self_ty);
debug!("tc={}", tc);
let met = match bound {
ty::BoundSend => tc.is_sendable(tcx),
ty::BoundSized => tc.is_sized(tcx),
ty::BoundCopy => tc.is_copy(tcx),
ty::BoundSync => tc.is_sync(tcx),
};

if met {
continue;
}

// FIXME -- This is kind of a hack: it requently happens
// that some earlier error prevents types from being fully
// inferred, and then we get a bunch of uninteresting
// errors saying something like "<generic #0> doesn't
// implement Sized". It may even be true that we could
// just skip over all checks where the self-ty is an
// inference variable, but I was afraid that there might
// be an inference variable created, registered as an
// obligation, and then never forced by writeback, and
// hence by skipping here we'd be ignoring the fact that
// we don't KNOW the type works out. Though even that
// would probably be harmless, given that we're only
// talking about builtin traits, which are known to be
// inhabited. But in any case I just threw in this check
// for has_errors() to be sure that compilation isn't
// happening anyway. In that case, why inundate the user.
if ty::type_needs_infer(self_ty) &&
tcx.sess.has_errors()
{
debug!("skipping printout because self_ty={}",
self_ty.repr(tcx));
continue;
}

errors.push(
FulfillmentError::new(
(*obligation).clone(),
CodeSelectionError(Unimplemented)));
}

if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
}
68 changes: 23 additions & 45 deletions src/librustc/middle/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
* Trait Resolution. See doc.rs.
*/

use middle::mem_categorization::Typer;
use middle::subst;
use middle::ty;
use middle::typeck::infer::InferCtxt;
use std::rc::Rc;
use syntax::ast;
use syntax::codemap::{Span, DUMMY_SP};
use util::nodemap::DefIdMap;

pub use self::fulfill::FulfillmentContext;
pub use self::select::SelectionContext;
Expand Down Expand Up @@ -208,50 +208,29 @@ pub struct VtableParamData {
pub bound: Rc<ty::TraitRef>,
}

pub fn try_select_obligation(infcx: &InferCtxt,
param_env: &ty::ParameterEnvironment,
unboxed_closures: &DefIdMap<ty::UnboxedClosure>,
obligation: &Obligation)
-> SelectionResult<Selection>
{
/*!
* Attempts to select the impl/bound/etc for the obligation
* given. Returns `None` if we are unable to resolve, either
* because of ambiguity or due to insufficient inference. Note
* that selection is a shallow process and hence the result may
* contain nested obligations that must be resolved. The caller is
* responsible for ensuring that those get resolved. (But see
* `try_select_obligation_deep` below.)
*/

let selcx = select::SelectionContext::new(infcx, param_env, unboxed_closures);
selcx.select(obligation)
}

pub fn evaluate_obligation(infcx: &InferCtxt,
param_env: &ty::ParameterEnvironment,
obligation: &Obligation,
unboxed_closures: &DefIdMap<ty::UnboxedClosure>)
-> EvaluationResult
pub fn evaluate_obligation<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
param_env: &ty::ParameterEnvironment,
obligation: &Obligation,
typer: &Typer<'tcx>)
-> EvaluationResult
{
/*!
* Attempts to resolve the obligation given. Returns `None` if
* we are unable to resolve, either because of ambiguity or
* due to insufficient inference.
*/

let selcx = select::SelectionContext::new(infcx, param_env,
unboxed_closures);
let mut selcx = select::SelectionContext::new(infcx, param_env, typer);
selcx.evaluate_obligation(obligation)
}

pub fn evaluate_impl(infcx: &InferCtxt,
param_env: &ty::ParameterEnvironment,
unboxed_closures: &DefIdMap<ty::UnboxedClosure>,
cause: ObligationCause,
impl_def_id: ast::DefId,
self_ty: ty::t)
-> EvaluationResult
pub fn evaluate_impl<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
param_env: &ty::ParameterEnvironment,
typer: &Typer<'tcx>,
cause: ObligationCause,
impl_def_id: ast::DefId,
self_ty: ty::t)
-> EvaluationResult
{
/*!
* Tests whether the impl `impl_def_id` can be applied to the self
Expand All @@ -264,17 +243,17 @@ pub fn evaluate_impl(infcx: &InferCtxt,
* (yes/no/unknown).
*/

let selcx = select::SelectionContext::new(infcx, param_env, unboxed_closures);
let mut selcx = select::SelectionContext::new(infcx, param_env, typer);
selcx.evaluate_impl(impl_def_id, cause, self_ty)
}

pub fn select_inherent_impl(infcx: &InferCtxt,
param_env: &ty::ParameterEnvironment,
unboxed_closures: &DefIdMap<ty::UnboxedClosure>,
cause: ObligationCause,
impl_def_id: ast::DefId,
self_ty: ty::t)
-> SelectionResult<VtableImplData<Obligation>>
pub fn select_inherent_impl<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
param_env: &ty::ParameterEnvironment,
typer: &Typer<'tcx>,
cause: ObligationCause,
impl_def_id: ast::DefId,
self_ty: ty::t)
-> SelectionResult<VtableImplData<Obligation>>
{
/*!
* Matches the self type of the inherent impl `impl_def_id`
Expand All @@ -293,8 +272,7 @@ pub fn select_inherent_impl(infcx: &InferCtxt,
// `try_resolve_obligation()`.
assert!(ty::impl_trait_ref(infcx.tcx, impl_def_id).is_none());

let selcx = select::SelectionContext::new(infcx, param_env,
unboxed_closures);
let mut selcx = select::SelectionContext::new(infcx, param_env, typer);
selcx.select_inherent_impl(impl_def_id, cause, self_ty)
}

Expand Down

0 comments on commit effb363

Please sign in to comment.