rustc: Wrap users of InferCtxt in an anonymous scope.

This commit is contained in:
Eduard Burtescu 2016-03-25 05:22:44 +02:00
parent 8a704f6dc7
commit 12e56ea56b
31 changed files with 853 additions and 890 deletions

View File

@ -385,12 +385,21 @@ impl fmt::Display for FixupError {
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: &'a RefCell<ty::Tables<'tcx>>,
param_env: Option<ty::ParameterEnvironment<'tcx>>,
projection_mode: ProjectionMode)
-> Self {
InferCtxt {
pub fn enter<F, R>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: Option<ty::Tables<'tcx>>,
param_env: Option<ty::ParameterEnvironment<'tcx>>,
projection_mode: ProjectionMode,
f: F) -> R
where F: for<'b> FnOnce(InferCtxt<'b, 'tcx, 'tcx>) -> R
{
let new_tables;
let tables = if let Some(tables) = tables {
new_tables = RefCell::new(tables);
&new_tables
} else {
&tcx.tables
};
f(InferCtxt {
tcx: tcx,
tables: tables,
type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
@ -403,16 +412,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx, 'tcx> {
projection_mode: projection_mode,
tainted_by_errors_flag: Cell::new(false),
err_count_on_creation: tcx.sess.err_count()
}
})
}
pub fn normalizing(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: &'a RefCell<ty::Tables<'tcx>>,
projection_mode: ProjectionMode)
-> Self {
let mut infcx = InferCtxt::new(tcx, tables, None, projection_mode);
infcx.normalize = true;
infcx
pub fn enter_normalizing<F, R>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
projection_mode: ProjectionMode,
f: F) -> R
where F: for<'b> FnOnce(InferCtxt<'b, 'tcx, 'tcx>) -> R
{
InferCtxt::enter(tcx, None, None, projection_mode, |mut infcx| {
infcx.normalize = true;
f(infcx)
})
}
}
@ -453,23 +464,23 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
return value;
}
let infcx = InferCtxt::new(self, &self.tables, None, ProjectionMode::Any);
let mut selcx = traits::SelectionContext::new(&infcx);
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: result, obligations } =
traits::normalize(&mut selcx, cause, &value);
InferCtxt::enter(self, None, None, ProjectionMode::Any, |infcx| {
let mut selcx = traits::SelectionContext::new(&infcx);
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: result, obligations } =
traits::normalize(&mut selcx, cause, &value);
debug!("normalize_associated_type: result={:?} obligations={:?}",
result,
obligations);
debug!("normalize_associated_type: result={:?} obligations={:?}",
result, obligations);
let mut fulfill_cx = traits::FulfillmentContext::new();
let mut fulfill_cx = traits::FulfillmentContext::new();
for obligation in obligations {
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
for obligation in obligations {
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
})
}
}

View File

@ -36,13 +36,12 @@ struct ItemVisitor<'a, 'tcx: 'a> {
impl<'a, 'tcx> ItemVisitor<'a, 'tcx> {
fn visit_const(&mut self, item_id: ast::NodeId, expr: &hir::Expr) {
let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
let infcx = InferCtxt::new(self.tcx, &self.tcx.tables,
Some(param_env),
ProjectionMode::Any);
let mut visitor = ExprVisitor {
infcx: &infcx
};
visitor.visit_expr(expr);
InferCtxt::enter(self.tcx, None, Some(param_env), ProjectionMode::Any, |infcx| {
let mut visitor = ExprVisitor {
infcx: &infcx
};
visitor.visit_expr(expr);
});
}
}
@ -115,12 +114,12 @@ impl<'a, 'tcx> ExprVisitor<'a, 'tcx, 'tcx> {
impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
// const, static and N in [T; N].
fn visit_expr(&mut self, expr: &hir::Expr) {
let infcx = InferCtxt::new(self.tcx, &self.tcx.tables,
None, ProjectionMode::Any);
let mut visitor = ExprVisitor {
infcx: &infcx
};
visitor.visit_expr(expr);
InferCtxt::enter(self.tcx, None, None, ProjectionMode::Any, |infcx| {
let mut visitor = ExprVisitor {
infcx: &infcx
};
visitor.visit_expr(expr);
});
}
fn visit_trait_item(&mut self, item: &hir::TraitItem) {
@ -141,21 +140,16 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
b: &'v hir::Block, s: Span, id: ast::NodeId) {
match fk {
FnKind::ItemFn(..) | FnKind::Method(..) => {
let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
let infcx = InferCtxt::new(self.tcx, &self.tcx.tables,
Some(param_env),
ProjectionMode::Any);
let mut visitor = ExprVisitor {
infcx: &infcx
};
visitor.visit_fn(fk, fd, b, s, id);
}
FnKind::Closure(..) => {
span_bug!(s, "intrinsicck: closure outside of function")
}
if let FnKind::Closure(..) = fk {
span_bug!(s, "intrinsicck: closure outside of function")
}
let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
InferCtxt::enter(self.tcx, None, Some(param_env), ProjectionMode::Any, |infcx| {
let mut visitor = ExprVisitor {
infcx: &infcx
};
visitor.visit_fn(fk, fd, b, s, id);
});
}
}

View File

@ -1488,18 +1488,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
let t_ret_subst = t_ret.subst(self.ir.tcx, &param_env.free_substs);
let infcx = InferCtxt::new(self.ir.tcx,
&self.ir.tcx.tables,
Some(param_env),
ProjectionMode::Any);
let cause = traits::ObligationCause::dummy();
let norm = traits::fully_normalize(&infcx,
cause,
&t_ret_subst);
let is_nil = InferCtxt::enter(self.ir.tcx, None, Some(param_env),
ProjectionMode::Any, |infcx| {
let cause = traits::ObligationCause::dummy();
traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil()
});
if norm.unwrap().is_nil() {
// for nil return types, it is ok to not return a value expl.
} else {
// for nil return types, it is ok to not return a value expl.
if !is_nil {
let ends_with_stmt = match body.expr {
None if !body.stmts.is_empty() =>
match body.stmts.last().unwrap().node {

View File

@ -37,7 +37,7 @@ pub use self::object_safety::MethodViolationCode;
pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
pub use self::specialize::{Overlap, specialization_graph, specializes, translate_substs};
pub use self::specialize::{OverlapError, specialization_graph, specializes, translate_substs};
pub use self::util::elaborate_predicates;
pub use self::util::supertraits;
pub use self::util::Supertraits;
@ -422,42 +422,43 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
let infcx = InferCtxt::new(tcx, &tcx.tables, Some(elaborated_env),
ProjectionMode::AnyFinal);
let predicates = match fully_normalize(&infcx,
cause,
&infcx.parameter_environment.caller_bounds) {
Ok(predicates) => predicates,
Err(errors) => {
infcx.report_fulfillment_errors(&errors);
return infcx.parameter_environment; // an unnormalized env is better than nothing
}
};
InferCtxt::enter(tcx, None, Some(elaborated_env), ProjectionMode::AnyFinal, |infcx| {
let predicates = match fully_normalize(&infcx, cause,
&infcx.parameter_environment.caller_bounds) {
Ok(predicates) => predicates,
Err(errors) => {
infcx.report_fulfillment_errors(&errors);
// An unnormalized env is better than nothing.
return infcx.parameter_environment;
}
};
debug!("normalize_param_env_or_error: normalized predicates={:?}",
predicates);
debug!("normalize_param_env_or_error: normalized predicates={:?}",
predicates);
let free_regions = FreeRegionMap::new();
infcx.resolve_regions_and_report_errors(&free_regions, body_id);
let predicates = match infcx.fully_resolve(&predicates) {
Ok(predicates) => predicates,
Err(fixup_err) => {
// If we encounter a fixup error, it means that some type
// variable wound up unconstrained. I actually don't know
// if this can happen, and I certainly don't expect it to
// happen often, but if it did happen it probably
// represents a legitimate failure due to some kind of
// unconstrained variable, and it seems better not to ICE,
// all things considered.
tcx.sess.span_err(span, &fixup_err.to_string());
return infcx.parameter_environment; // an unnormalized env is better than nothing
}
};
let free_regions = FreeRegionMap::new();
infcx.resolve_regions_and_report_errors(&free_regions, body_id);
let predicates = match infcx.fully_resolve(&predicates) {
Ok(predicates) => predicates,
Err(fixup_err) => {
// If we encounter a fixup error, it means that some type
// variable wound up unconstrained. I actually don't know
// if this can happen, and I certainly don't expect it to
// happen often, but if it did happen it probably
// represents a legitimate failure due to some kind of
// unconstrained variable, and it seems better not to ICE,
// all things considered.
tcx.sess.span_err(span, &fixup_err.to_string());
// An unnormalized env is better than nothing.
return infcx.parameter_environment;
}
};
debug!("normalize_param_env_or_error: resolved predicates={:?}",
predicates);
debug!("normalize_param_env_or_error: resolved predicates={:?}",
predicates);
infcx.parameter_environment.with_caller_bounds(predicates)
infcx.parameter_environment.with_caller_bounds(predicates)
})
}
pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx, 'tcx>,

View File

@ -31,10 +31,10 @@ use syntax::codemap::DUMMY_SP;
pub mod specialization_graph;
/// Information pertinent to an overlapping impl error.
pub struct Overlap<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
pub in_context: InferCtxt<'a, 'gcx, 'tcx>,
pub struct OverlapError {
pub with_impl: DefId,
pub on_trait_ref: ty::TraitRef<'tcx>,
pub trait_desc: String,
pub self_desc: Option<String>
}
/// Given a subst for the requested impl, translate it to a subst
@ -135,8 +135,6 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
return false;
}
let mut infcx = InferCtxt::normalizing(tcx, &tcx.tables, ProjectionMode::Topmost);
// create a parameter environment corresponding to a (skolemized) instantiation of impl1
let scheme = tcx.lookup_item_type(impl1_def_id);
let predicates = tcx.lookup_predicates(impl1_def_id);
@ -148,18 +146,21 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
.unwrap()
.subst(tcx, &penv.free_substs);
// Normalize the trait reference, adding any obligations that arise into the impl1 assumptions
let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
let selcx = &mut SelectionContext::new(&infcx);
traits::normalize(selcx, ObligationCause::dummy(), &impl1_trait_ref)
};
penv.caller_bounds.extend(normalization_obligations.into_iter().map(|o| o.predicate));
InferCtxt::enter_normalizing(tcx, ProjectionMode::Topmost, |mut infcx| {
// Normalize the trait reference, adding any obligations
// that arise into the impl1 assumptions.
let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
let selcx = &mut SelectionContext::new(&infcx);
traits::normalize(selcx, ObligationCause::dummy(), &impl1_trait_ref)
};
penv.caller_bounds.extend(normalization_obligations.into_iter().map(|o| o.predicate));
// Install the parameter environment, taking the predicates of impl1 as assumptions:
infcx.parameter_environment = penv;
// Install the parameter environment, taking the predicates of impl1 as assumptions:
infcx.parameter_environment = penv;
// Attempt to prove that impl2 applies, given all of the above.
fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok()
// Attempt to prove that impl2 applies, given all of the above.
fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok()
})
}
/// Attempt to fulfill all obligations of `target_impl` after unification with

View File

@ -11,7 +11,7 @@
use std::cell;
use std::rc::Rc;
use super::{Overlap, specializes};
use super::{OverlapError, specializes};
use hir::def_id::DefId;
use infer::InferCtxt;
@ -66,7 +66,7 @@ struct Children {
}
/// The result of attempting to insert an impl into a group of children.
enum InsertResult<'a, 'tcx: 'a> {
enum Inserted {
/// The impl was inserted as a new child in this group of children.
BecameNewSibling,
@ -75,10 +75,6 @@ enum InsertResult<'a, 'tcx: 'a> {
/// The impl is a specialization of an existing child.
ShouldRecurseOn(DefId),
/// The impl has an unresolvable overlap with an existing child (neither
/// specializes the other).
Overlapped(Overlap<'a, 'tcx, 'tcx>),
}
impl<'a, 'tcx> Children {
@ -107,7 +103,7 @@ impl<'a, 'tcx> Children {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_def_id: DefId,
simplified_self: Option<SimplifiedType>)
-> InsertResult<'a, 'tcx>
-> Result<Inserted, OverlapError>
{
for slot in match simplified_self {
Some(sty) => self.filtered_mut(sty),
@ -115,41 +111,62 @@ impl<'a, 'tcx> Children {
} {
let possible_sibling = *slot;
let infcx = InferCtxt::new(tcx, &tcx.tables, None, ProjectionMode::Topmost);
let overlap = traits::overlapping_impls(&infcx, possible_sibling, impl_def_id);
let (le, ge) = InferCtxt::enter(tcx, None, None,
ProjectionMode::Topmost, |infcx| {
let overlap = traits::overlapping_impls(&infcx,
possible_sibling,
impl_def_id);
if let Some(impl_header) = overlap {
let le = specializes(tcx, impl_def_id, possible_sibling);
let ge = specializes(tcx, possible_sibling, impl_def_id);
if let Some(impl_header) = overlap {
let le = specializes(tcx, impl_def_id, possible_sibling);
let ge = specializes(tcx, possible_sibling, impl_def_id);
if le == ge {
// overlap, but no specialization; error out
let trait_ref = impl_header.trait_ref.unwrap();
Err(OverlapError {
with_impl: possible_sibling,
trait_desc: trait_ref.to_string(),
self_desc: trait_ref.substs.self_ty().and_then(|ty| {
// only report the Self type if it has at least
// some outer concrete shell; otherwise, it's
// not adding much information.
if ty.has_concrete_skeleton() {
Some(ty.to_string())
} else {
None
}
})
})
} else {
Ok((le, ge))
}
} else {
Ok((false, false))
}
})?;
if le && !ge {
debug!("descending as child of TraitRef {:?}",
tcx.impl_trait_ref(possible_sibling).unwrap());
if le && !ge {
debug!("descending as child of TraitRef {:?}",
tcx.impl_trait_ref(possible_sibling).unwrap());
// the impl specializes possible_sibling
return InsertResult::ShouldRecurseOn(possible_sibling);
} else if ge && !le {
debug!("placing as parent of TraitRef {:?}",
tcx.impl_trait_ref(possible_sibling).unwrap());
// the impl specializes possible_sibling
return Ok(Inserted::ShouldRecurseOn(possible_sibling));
} else if ge && !le {
debug!("placing as parent of TraitRef {:?}",
tcx.impl_trait_ref(possible_sibling).unwrap());
// possible_sibling specializes the impl
*slot = impl_def_id;
return InsertResult::Replaced(possible_sibling);
} else {
// overlap, but no specialization; error out
return InsertResult::Overlapped(Overlap {
with_impl: possible_sibling,
on_trait_ref: impl_header.trait_ref.unwrap(),
in_context: infcx,
});
}
return Ok(Inserted::Replaced(possible_sibling));
} else {
// no overlap (error bailed already via ?)
}
}
// no overlap with any potential siblings, so add as a new sibling
debug!("placing as new sibling");
self.insert_blindly(tcx, impl_def_id);
InsertResult::BecameNewSibling
Ok(Inserted::BecameNewSibling)
}
fn iter_mut(&'a mut self) -> Box<Iterator<Item = &'a mut DefId> + 'a> {
@ -178,7 +195,7 @@ impl<'a, 'tcx> Graph {
pub fn insert(&mut self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_def_id: DefId)
-> Result<(), Overlap<'a, 'tcx, 'tcx>> {
-> Result<(), OverlapError> {
assert!(impl_def_id.is_local());
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
@ -207,10 +224,10 @@ impl<'a, 'tcx> Graph {
// Descend the specialization tree, where `parent` is the current parent node
loop {
use self::InsertResult::*;
use self::Inserted::*;
let insert_result = self.children.entry(parent).or_insert(Children::new())
.insert(tcx, impl_def_id, simplified);
.insert(tcx, impl_def_id, simplified)?;
match insert_result {
BecameNewSibling => {
@ -226,9 +243,6 @@ impl<'a, 'tcx> Graph {
ShouldRecurseOn(new_parent) => {
parent = new_parent;
}
Overlapped(error) => {
return Err(error);
}
}
}

View File

@ -197,7 +197,7 @@ impl<'a, 'tcx> TraitDef<'tcx> {
pub fn add_impl_for_specialization(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_def_id: DefId)
-> Result<(), traits::Overlap<'a, 'tcx, 'tcx>> {
-> Result<(), traits::OverlapError> {
assert!(impl_def_id.is_local());
self.specialization_graph.borrow_mut()

View File

@ -134,34 +134,34 @@ impl<'tcx> ParameterEnvironment<'tcx> {
self_type: Ty<'tcx>, span: Span)
-> Result<(),CopyImplementationError> {
// FIXME: (@jroesch) float this code up
let infcx = InferCtxt::new(tcx, &tcx.tables, Some(self.clone()),
ProjectionMode::Topmost);
let adt = match self_type.sty {
ty::TyStruct(struct_def, substs) => {
for field in struct_def.all_fields() {
let field_ty = field.ty(tcx, substs);
if infcx.type_moves_by_default(field_ty, span) {
return Err(CopyImplementationError::InfrigingField(
field.name))
}
}
struct_def
}
ty::TyEnum(enum_def, substs) => {
for variant in &enum_def.variants {
for field in &variant.fields {
let adt = InferCtxt::enter(tcx, None, Some(self.clone()),
ProjectionMode::Topmost, |infcx| {
match self_type.sty {
ty::TyStruct(struct_def, substs) => {
for field in struct_def.all_fields() {
let field_ty = field.ty(tcx, substs);
if infcx.type_moves_by_default(field_ty, span) {
return Err(CopyImplementationError::InfrigingVariant(
variant.name))
return Err(CopyImplementationError::InfrigingField(
field.name))
}
}
Ok(struct_def)
}
enum_def
ty::TyEnum(enum_def, substs) => {
for variant in &enum_def.variants {
for field in &variant.fields {
let field_ty = field.ty(tcx, substs);
if infcx.type_moves_by_default(field_ty, span) {
return Err(CopyImplementationError::InfrigingVariant(
variant.name))
}
}
}
Ok(enum_def)
}
_ => Err(CopyImplementationError::NotAnAdt)
}
_ => return Err(CopyImplementationError::NotAnAdt),
};
})?;
if adt.has_dtor() {
return Err(CopyImplementationError::HasDestructor)
@ -512,16 +512,9 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
param_env: &ParameterEnvironment<'tcx>,
bound: ty::BuiltinBound, span: Span) -> bool
{
let infcx = InferCtxt::new(tcx, &tcx.tables, Some(param_env.clone()),
ProjectionMode::Topmost);
let is_impld = traits::type_known_to_meet_builtin_bound(&infcx,
self, bound, span);
debug!("Ty::impls_bound({:?}, {:?}) = {:?}",
self, bound, is_impld);
is_impld
InferCtxt::enter(tcx, None, Some(param_env.clone()), ProjectionMode::Topmost, |infcx| {
traits::type_known_to_meet_builtin_bound(&infcx, self, bound, span)
})
}
// FIXME (@jroesch): I made this public to use it, not sure if should be private

View File

@ -203,21 +203,17 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
debug!("check_loans(body id={})", body.id);
let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
let infcx = InferCtxt::new(bccx.tcx, &bccx.tcx.tables, Some(param_env),
ProjectionMode::AnyFinal);
let mut clcx = CheckLoanCtxt {
bccx: bccx,
dfcx_loans: dfcx_loans,
move_data: move_data,
all_loans: all_loans,
param_env: &infcx.parameter_environment
};
{
InferCtxt::enter(bccx.tcx, None, Some(param_env), ProjectionMode::AnyFinal, |infcx| {
let mut clcx = CheckLoanCtxt {
bccx: bccx,
dfcx_loans: dfcx_loans,
move_data: move_data,
all_loans: all_loans,
param_env: &infcx.parameter_environment
};
let mut euv = euv::ExprUseVisitor::new(&mut clcx, &infcx);
euv.walk_fn(decl, body);
}
});
}
#[derive(PartialEq)]

View File

@ -56,12 +56,10 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
};
let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
let infcx = InferCtxt::new(bccx.tcx, &bccx.tcx.tables, Some(param_env),
ProjectionMode::AnyFinal);
{
InferCtxt::enter(bccx.tcx, None, Some(param_env), ProjectionMode::AnyFinal, |infcx| {
let mut euv = euv::ExprUseVisitor::new(&mut glcx, &infcx);
euv.walk_fn(decl, body);
}
});
glcx.report_potential_errors();
let GatherLoanCtxt { all_loans, move_data, .. } = glcx;
@ -527,15 +525,17 @@ struct StaticInitializerCtxt<'a, 'tcx: 'a> {
impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> {
fn visit_expr(&mut self, ex: &Expr) {
if let hir::ExprAddrOf(mutbl, ref base) = ex.node {
let infcx = InferCtxt::new(self.bccx.tcx, &self.bccx.tcx.tables, None,
ProjectionMode::AnyFinal);
let mc = mc::MemCategorizationContext::new(&infcx);
let base_cmt = mc.cat_expr(&base).unwrap();
let borrow_kind = ty::BorrowKind::from_mutbl(mutbl);
// Check that we don't allow borrows of unsafe static items.
if check_aliasability(self.bccx, ex.span,
BorrowViolation(euv::AddrOf),
base_cmt, borrow_kind).is_err() {
let err = InferCtxt::enter(self.bccx.tcx, None, None,
ProjectionMode::AnyFinal, |infcx| {
let mc = mc::MemCategorizationContext::new(&infcx);
let base_cmt = mc.cat_expr(&base).unwrap();
let borrow_kind = ty::BorrowKind::from_mutbl(mutbl);
// Check that we don't allow borrows of unsafe static items.
check_aliasability(self.bccx, ex.span,
BorrowViolation(euv::AddrOf),
base_cmt, borrow_kind).is_err()
});
if err {
return; // reported an error, no sense in reporting more.
}
}

View File

@ -1123,12 +1123,12 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
PatKind::Ident(hir::BindByValue(_), _, ref sub) => {
let pat_ty = tcx.node_id_to_type(p.id);
//FIXME: (@jroesch) this code should be floated up as well
let infcx = InferCtxt::new(cx.tcx, &cx.tcx.tables,
Some(cx.param_env.clone()),
ProjectionMode::AnyFinal);
if infcx.type_moves_by_default(pat_ty, pat.span) {
check_move(p, sub.as_ref().map(|p| &**p));
}
InferCtxt::enter(cx.tcx, None, Some(cx.param_env.clone()),
ProjectionMode::AnyFinal, |infcx| {
if infcx.type_moves_by_default(pat_ty, pat.span) {
check_move(p, sub.as_ref().map(|p| &**p));
}
});
}
PatKind::Ident(hir::BindByRef(_), _, _) => {
}
@ -1150,16 +1150,14 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
/// assign.
fn check_for_mutation_in_guard<'a, 'tcx>(cx: &'a MatchCheckCtxt<'a, 'tcx>,
guard: &hir::Expr) {
let mut checker = MutationChecker {
cx: cx,
};
let infcx = InferCtxt::new(cx.tcx, &cx.tcx.tables,
Some(checker.cx.param_env.clone()),
ProjectionMode::AnyFinal);
let mut visitor = ExprUseVisitor::new(&mut checker, &infcx);
visitor.walk_expr(guard);
InferCtxt::enter(cx.tcx, None, Some(cx.param_env.clone()),
ProjectionMode::AnyFinal, |infcx| {
let mut checker = MutationChecker {
cx: cx,
};
let mut visitor = ExprUseVisitor::new(&mut checker, &infcx);
visitor.walk_expr(guard);
});
}
struct MutationChecker<'a, 'tcx: 'a> {

View File

@ -1014,48 +1014,47 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
trait_ref);
tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
let infcx = InferCtxt::new(tcx, &tcx.tables, None, ProjectionMode::AnyFinal);
InferCtxt::enter(tcx, None, None, ProjectionMode::AnyFinal, |infcx| {
let mut selcx = traits::SelectionContext::new(&infcx);
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
trait_ref.to_poly_trait_predicate());
let selection = match selcx.select(&obligation) {
Ok(Some(vtable)) => vtable,
// Still ambiguous, so give up and let the caller decide whether this
// expression is really needed yet. Some associated constant values
// can't be evaluated until monomorphization is done in trans.
Ok(None) => {
return None
}
Err(_) => {
return None
}
};
let mut selcx = traits::SelectionContext::new(&infcx);
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
trait_ref.to_poly_trait_predicate());
let selection = match selcx.select(&obligation) {
Ok(Some(vtable)) => vtable,
// Still ambiguous, so give up and let the caller decide whether this
// expression is really needed yet. Some associated constant values
// can't be evaluated until monomorphization is done in trans.
Ok(None) => {
return None
}
Err(_) => {
return None
}
};
// NOTE: this code does not currently account for specialization, but when
// it does so, it should hook into the ProjectionMode to determine when the
// constant should resolve; this will also require plumbing through to this
// function whether we are in "trans mode" to pick the right ProjectionMode
// when constructing the inference context above.
match selection {
traits::VtableImpl(ref impl_data) => {
match tcx.associated_consts(impl_data.impl_def_id)
.iter().find(|ic| ic.name == ti.name) {
Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
None => match ti.node {
hir::ConstTraitItem(ref ty, Some(ref expr)) => {
Some((&*expr, tcx.ast_ty_to_prim_ty(ty)))
// NOTE: this code does not currently account for specialization, but when
// it does so, it should hook into the ProjectionMode to determine when the
// constant should resolve; this will also require plumbing through to this
// function whether we are in "trans mode" to pick the right ProjectionMode
// when constructing the inference context above.
match selection {
traits::VtableImpl(ref impl_data) => {
match tcx.associated_consts(impl_data.impl_def_id)
.iter().find(|ic| ic.name == ti.name) {
Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
None => match ti.node {
hir::ConstTraitItem(ref ty, Some(ref expr)) => {
Some((&*expr, tcx.ast_ty_to_prim_ty(ty)))
},
_ => None,
},
_ => None,
},
}
}
_ => {
span_bug!(ti.span,
"resolve_trait_associated_const: unexpected vtable type")
}
}
_ => {
span_bug!(
ti.span,
"resolve_trait_associated_const: unexpected vtable type")
}
}
})
}
fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty::Ty) -> CastResult {

View File

@ -138,25 +138,25 @@ fn test_env<F>(source_string: &str,
let region_map = region::resolve_crate(&sess, &ast_map);
let index = stability::Index::new(&ast_map);
TyCtxt::create_and_enter(&sess,
&arenas,
resolutions.def_map,
named_region_map.unwrap(),
ast_map,
resolutions.freevars,
resolutions.maybe_unused_trait_imports,
region_map,
lang_items,
index,
"test_crate",
|tcx| {
let infcx = InferCtxt::new(tcx, &tcx.tables, None,
ProjectionMode::AnyFinal);
body(Env { infcx: &infcx });
let free_regions = FreeRegionMap::new();
infcx.resolve_regions_and_report_errors(&free_regions,
ast::CRATE_NODE_ID);
assert_eq!(tcx.sess.err_count(), expected_err_count);
});
&arenas,
resolutions.def_map,
named_region_map.unwrap(),
ast_map,
resolutions.freevars,
resolutions.maybe_unused_trait_imports,
region_map,
lang_items,
index,
"test_crate",
|tcx| {
InferCtxt::enter(tcx, None, None, ProjectionMode::AnyFinal, |infcx| {
body(Env { infcx: &infcx });
let free_regions = FreeRegionMap::new();
infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID);
assert_eq!(tcx.sess.err_count(), expected_err_count);
});
});
}
impl<'a, 'tcx> Env<'a, 'tcx> {

View File

@ -869,37 +869,37 @@ impl LateLintPass for UnconditionalRecursion {
// checking, so it's always local
let node_id = tcx.map.as_local_node_id(method.def_id).unwrap();
let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
let infcx = InferCtxt::new(tcx, &tcx.tables, Some(param_env),
ProjectionMode::AnyFinal);
let mut selcx = traits::SelectionContext::new(&infcx);
match selcx.select(&obligation) {
// The method comes from a `T: Trait` bound.
// If `T` is `Self`, then this call is inside
// a default method definition.
Ok(Some(traits::VtableParam(_))) => {
let self_ty = callee_substs.self_ty();
let on_self = self_ty.map_or(false, |t| t.is_self());
// We can only be recurring in a default
// method if we're being called literally
// on the `Self` type.
on_self && callee_id == method.def_id
}
let param_env = Some(ty::ParameterEnvironment::for_item(tcx, node_id));
InferCtxt::enter(tcx, None, param_env, ProjectionMode::AnyFinal, |infcx| {
let mut selcx = traits::SelectionContext::new(&infcx);
match selcx.select(&obligation) {
// The method comes from a `T: Trait` bound.
// If `T` is `Self`, then this call is inside
// a default method definition.
Ok(Some(traits::VtableParam(_))) => {
let self_ty = callee_substs.self_ty();
let on_self = self_ty.map_or(false, |t| t.is_self());
// We can only be recurring in a default
// method if we're being called literally
// on the `Self` type.
on_self && callee_id == method.def_id
}
// The `impl` is known, so we check that with a
// special case:
Ok(Some(traits::VtableImpl(vtable_impl))) => {
let container = ty::ImplContainer(vtable_impl.impl_def_id);
// It matches if it comes from the same impl,
// and has the same method name.
container == method.container
&& callee_item.name() == method.name
}
// The `impl` is known, so we check that with a
// special case:
Ok(Some(traits::VtableImpl(vtable_impl))) => {
let container = ty::ImplContainer(vtable_impl.impl_def_id);
// It matches if it comes from the same impl,
// and has the same method name.
container == method.container
&& callee_item.name() == method.name
}
// There's no way to know if this call is
// recursive, so we assume it's not.
_ => return false
}
// There's no way to know if this call is
// recursive, so we assume it's not.
_ => false
}
})
}
}
}

View File

@ -75,13 +75,12 @@ impl<'a, 'tcx> BuildMir<'a, 'tcx> {
};
let param_env = ty::ParameterEnvironment::for_item(self.tcx, src.item_id());
let infcx = InferCtxt::new(self.tcx, &self.tcx.tables, Some(param_env),
ProjectionMode::AnyFinal);
let (mir, scope_auxiliary) = f(Cx::new(&infcx, constness));
pretty::dump_mir(self.tcx, "mir_map", &0, src, &mir, Some(&scope_auxiliary));
let mir = InferCtxt::enter(self.tcx, None, Some(param_env),
ProjectionMode::AnyFinal, |infcx| {
let (mir, scope_auxiliary) = f(Cx::new(&infcx, constness));
pretty::dump_mir(self.tcx, "mir_map", &0, src, &mir, Some(&scope_auxiliary));
mir
});
assert!(self.map.map.insert(src.item_id(), mir).is_none())
}

View File

@ -1019,18 +1019,18 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants {
// Statics must be Sync.
if mode == Mode::Static {
let ty = mir.return_ty.unwrap();
let infcx = InferCtxt::new(tcx, &tcx.tables, None,
ProjectionMode::AnyFinal);
let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
let mut fulfillment_cx = traits::FulfillmentContext::new();
fulfillment_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
infcx.report_fulfillment_errors(&err);
}
InferCtxt::enter(tcx, None, None, ProjectionMode::AnyFinal, |infcx| {
let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
let mut fulfillment_cx = traits::FulfillmentContext::new();
fulfillment_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
infcx.report_fulfillment_errors(&err);
}
if let Err(errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) {
infcx.report_fulfillment_errors_as_warnings(&errors, id);
}
if let Err(errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) {
infcx.report_fulfillment_errors_as_warnings(&errors, id);
}
});
}
}
}

View File

@ -584,19 +584,19 @@ impl<'tcx> MirPass<'tcx> for TypeckMir {
return;
}
let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
let infcx = InferCtxt::new(tcx, &tcx.tables, Some(param_env),
ProjectionMode::AnyFinal);
let mut checker = TypeChecker::new(&infcx);
{
let mut verifier = TypeVerifier::new(&mut checker, mir);
verifier.visit_mir(mir);
if verifier.errors_reported {
// don't do further checks to avoid ICEs
return;
InferCtxt::enter(tcx, None, Some(param_env), ProjectionMode::AnyFinal, |infcx| {
let mut checker = TypeChecker::new(&infcx);
{
let mut verifier = TypeVerifier::new(&mut checker, mir);
verifier.visit_mir(mir);
if verifier.errors_reported {
// don't do further checks to avoid ICEs
return;
}
}
}
checker.typeck_mir(mir);
checker.verify_obligations(mir);
checker.typeck_mir(mir);
checker.verify_obligations(mir);
});
}
}

View File

@ -88,17 +88,16 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
}
fn with_euv<'b, F, R>(&'b mut self, item_id: Option<ast::NodeId>, f: F) -> R where
F: for<'c> FnOnce(&mut euv::ExprUseVisitor<'b, 'c, 'tcx, 'tcx>) -> R,
F: for<'c> FnOnce(&mut euv::ExprUseVisitor<'c, 'c, 'tcx, 'tcx>) -> R,
{
let param_env = match item_id {
Some(item_id) => ty::ParameterEnvironment::for_item(self.tcx, item_id),
None => self.tcx.empty_parameter_environment()
};
let infcx = InferCtxt::new(self.tcx, &self.tcx.tables, Some(param_env),
ProjectionMode::AnyFinal);
f(&mut euv::ExprUseVisitor::new(self, &infcx))
InferCtxt::enter(self.tcx, None, Some(param_env), ProjectionMode::AnyFinal, |infcx| {
f(&mut euv::ExprUseVisitor::new(self, &infcx))
})
}
fn global_expr(&mut self, mode: Mode, expr: &hir::Expr) -> ConstQualif {

View File

@ -39,16 +39,17 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> {
b: &'v hir::Block,
s: Span,
fn_id: ast::NodeId) {
{
// FIXME (@jroesch) change this to be an inference context
let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
let infcx = InferCtxt::new(self.tcx, &self.tcx.tables,
Some(param_env.clone()),
ProjectionMode::AnyFinal);
let mut delegate = RvalueContextDelegate { tcx: self.tcx, param_env: &param_env };
// FIXME (@jroesch) change this to be an inference context
let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
InferCtxt::enter(self.tcx, None, Some(param_env.clone()),
ProjectionMode::AnyFinal, |infcx| {
let mut delegate = RvalueContextDelegate {
tcx: self.tcx,
param_env: &param_env
};
let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
euv.walk_fn(fd, b);
}
});
intravisit::walk_fn(self, fk, fd, b, s)
}
}

View File

@ -1466,12 +1466,10 @@ fn is_discr_reassigned(bcx: Block, discr: &hir::Expr, body: &hir::Expr) -> bool
field: field,
reassigned: false
};
{
let infcx = InferCtxt::normalizing(bcx.tcx(), &bcx.tcx().tables,
ProjectionMode::Any);
InferCtxt::enter_normalizing(bcx.tcx(), ProjectionMode::Any, |infcx| {
let mut visitor = euv::ExprUseVisitor::new(&mut rc, &infcx);
visitor.walk_expr(body);
}
});
rc.reassigned
}

View File

@ -12,8 +12,6 @@ use arena::TypedArena;
use back::symbol_names;
use llvm::{ValueRef, get_param, get_params};
use rustc::hir::def_id::DefId;
use rustc::infer::InferCtxt;
use rustc::traits::ProjectionMode;
use abi::{Abi, FnType};
use adt;
use attributes;
@ -155,8 +153,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let symbol = symbol_names::exported_name(ccx, &instance);
// Compute the rust-call form of the closure call method.
let infcx = InferCtxt::normalizing(tcx, &tcx.tables, ProjectionMode::Any);
let sig = &infcx.closure_type(closure_id, &substs).sig;
let sig = &ty::Tables::closure_type(&tcx.tables, tcx, closure_id, &substs).sig;
let sig = tcx.erase_late_bound_regions(sig);
let sig = tcx.normalize_associated_type(&sig);
let closure_type = tcx.mk_closure_from_closure_substs(closure_id, Box::new(substs));
@ -220,11 +217,11 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
// this function (`trans_closure`) is invoked at the point
// of the closure expression.
let infcx = InferCtxt::normalizing(ccx.tcx(), &ccx.tcx().tables, ProjectionMode::Any);
let function_type = infcx.closure_type(closure_def_id, closure_substs);
let sig = tcx.erase_late_bound_regions(&function_type.sig);
let sig = ccx.tcx().normalize_associated_type(&sig);
let sig = &ty::Tables::closure_type(&tcx.tables, tcx,
closure_def_id,
closure_substs).sig;
let sig = tcx.erase_late_bound_regions(sig);
let sig = tcx.normalize_associated_type(&sig);
let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id,
Box::new(closure_substs.clone()));
@ -344,7 +341,6 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
closure_def_id, substs, Value(llreffn));
let tcx = ccx.tcx();
let infcx = InferCtxt::normalizing(ccx.tcx(), &ccx.tcx().tables, ProjectionMode::Any);
// Find a version of the closure type. Substitute static for the
// region since it doesn't really matter.
@ -352,7 +348,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), closure_ty);
// Make a version with the type of by-ref closure.
let ty::ClosureTy { unsafety, abi, mut sig } = infcx.closure_type(closure_def_id, &substs);
let ty::ClosureTy { unsafety, abi, mut sig } =
ty::Tables::closure_type(&tcx.tables, tcx, closure_def_id, &substs);
sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet
let llref_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
unsafety: unsafety,
@ -369,7 +366,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
sig.0.inputs[0] = closure_ty;
let sig = tcx.erase_late_bound_regions(&sig);
let sig = ccx.tcx().normalize_associated_type(&sig);
let sig = tcx.normalize_associated_type(&sig);
let fn_ty = FnType::new(ccx, abi, &sig, &[]);
let llonce_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {

View File

@ -1066,53 +1066,49 @@ pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
// Do the initial selection for the obligation. This yields the
// shallow result we are looking for -- that is, what specific impl.
let infcx = InferCtxt::normalizing(tcx, &tcx.tables, ProjectionMode::Any);
let mut selcx = SelectionContext::new(&infcx);
let vtable = InferCtxt::enter_normalizing(tcx, ProjectionMode::Any, |infcx| {
let mut selcx = SelectionContext::new(&infcx);
let obligation_cause = traits::ObligationCause::misc(span,
let obligation_cause = traits::ObligationCause::misc(span,
ast::DUMMY_NODE_ID);
let obligation = traits::Obligation::new(obligation_cause,
trait_ref.to_poly_trait_predicate());
let obligation = traits::Obligation::new(obligation_cause,
trait_ref.to_poly_trait_predicate());
let selection = match selcx.select(&obligation) {
Ok(Some(selection)) => selection,
Ok(None) => {
// Ambiguity can happen when monomorphizing during trans
// expands to some humongo type that never occurred
// statically -- this humongo type can then overflow,
// leading to an ambiguous result. So report this as an
// overflow bug, since I believe this is the only case
// where ambiguity can result.
debug!("Encountered ambiguity selecting `{:?}` during trans, \
presuming due to overflow",
trait_ref);
tcx.sess.span_fatal(
span,
"reached the recursion limit during monomorphization \
(selection ambiguity)");
}
Err(e) => {
span_bug!(
span,
"Encountered error `{:?}` selecting `{:?}` during trans",
e,
trait_ref)
}
};
let selection = match selcx.select(&obligation) {
Ok(Some(selection)) => selection,
Ok(None) => {
// Ambiguity can happen when monomorphizing during trans
// expands to some humongo type that never occurred
// statically -- this humongo type can then overflow,
// leading to an ambiguous result. So report this as an
// overflow bug, since I believe this is the only case
// where ambiguity can result.
debug!("Encountered ambiguity selecting `{:?}` during trans, \
presuming due to overflow",
trait_ref);
tcx.sess.span_fatal(span,
"reached the recursion limit during monomorphization \
(selection ambiguity)");
}
Err(e) => {
span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans",
e, trait_ref)
}
};
// Currently, we use a fulfillment context to completely resolve
// all nested obligations. This is because they can inform the
// inference of the impl's type parameters.
let mut fulfill_cx = traits::FulfillmentContext::new();
let vtable = selection.map(|predicate| {
fulfill_cx.register_predicate_obligation(&infcx, predicate);
});
let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable);
// Currently, we use a fulfillment context to completely resolve
// all nested obligations. This is because they can inform the
// inference of the impl's type parameters.
let mut fulfill_cx = traits::FulfillmentContext::new();
let vtable = selection.map(|predicate| {
fulfill_cx.register_predicate_obligation(&infcx, predicate);
});
let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable);
info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
vtable
})
info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
vtable
})
});
}
/// Normalizes the predicates and checks whether they hold. If this
@ -1126,21 +1122,22 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("normalize_and_test_predicates(predicates={:?})",
predicates);
let infcx = InferCtxt::normalizing(tcx, &tcx.tables, ProjectionMode::Any);
let mut selcx = SelectionContext::new(&infcx);
let mut fulfill_cx = traits::FulfillmentContext::new();
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: predicates, obligations } =
traits::normalize(&mut selcx, cause.clone(), &predicates);
for obligation in obligations {
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
for predicate in predicates {
let obligation = traits::Obligation::new(cause.clone(), predicate);
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
InferCtxt::enter_normalizing(tcx, ProjectionMode::Any, |infcx| {
let mut selcx = SelectionContext::new(&infcx);
let mut fulfill_cx = traits::FulfillmentContext::new();
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: predicates, obligations } =
traits::normalize(&mut selcx, cause.clone(), &predicates);
for obligation in obligations {
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
for predicate in predicates {
let obligation = traits::Obligation::new(cause.clone(), predicate);
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
infcx.drain_fulfillment_cx(&mut fulfill_cx, &()).is_ok()
infcx.drain_fulfillment_cx(&mut fulfill_cx, &()).is_ok()
})
}
pub fn langcall(bcx: Block,

View File

@ -314,13 +314,15 @@ pub fn get_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
let trait_def = tcx.lookup_trait_def(trait_def_id);
let infcx = InferCtxt::normalizing(tcx, &tcx.tables, ProjectionMode::Any);
match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() {
Some(node_item) => {
let substs = InferCtxt::enter_normalizing(tcx, ProjectionMode::Any, |infcx| {
traits::translate_substs(&infcx, impl_def_id, substs, node_item.node)
});
ImplMethod {
method: node_item.item,
substs: traits::translate_substs(&infcx, impl_def_id, substs, node_item.node),
substs: substs,
is_provided: node_item.node.is_from_trait(),
}
}

View File

@ -124,8 +124,10 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
cx.llsizingtypes().borrow_mut().insert(t, llsizingty);
// FIXME(eddyb) Temporary sanity check for ty::layout.
let infcx = InferCtxt::normalizing(cx.tcx(), &cx.tcx().tables, ProjectionMode::Any);
match t.layout(&infcx) {
let layout = InferCtxt::enter_normalizing(cx.tcx(), ProjectionMode::Any, |infcx| {
t.layout(&infcx)
});
match layout {
Ok(layout) => {
if !type_is_sized(cx.tcx(), t) {
if !layout.is_unsized() {

View File

@ -44,8 +44,6 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
impl_trait_ref);
let tcx = ccx.tcx;
let mut infcx = InferCtxt::new(tcx, &tcx.tables, None, ProjectionMode::AnyFinal);
let mut fulfillment_cx = traits::FulfillmentContext::new();
let trait_to_impl_substs = &impl_trait_ref.substs;
@ -206,165 +204,169 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let impl_bounds =
impl_m.predicates.instantiate(tcx, impl_to_skol_substs);
let (impl_bounds, _) =
infcx.replace_late_bound_regions_with_fresh_var(
impl_m_span,
infer::HigherRankedType,
&ty::Binder(impl_bounds));
debug!("compare_impl_method: impl_bounds={:?}",
impl_bounds);
InferCtxt::enter(tcx, None, None, ProjectionMode::AnyFinal, |mut infcx| {
let mut fulfillment_cx = traits::FulfillmentContext::new();
let (impl_bounds, _) =
infcx.replace_late_bound_regions_with_fresh_var(
impl_m_span,
infer::HigherRankedType,
&ty::Binder(impl_bounds));
debug!("compare_impl_method: impl_bounds={:?}",
impl_bounds);
// Normalize the associated types in the trait_bounds.
let trait_bounds = trait_m.predicates.instantiate(tcx, &trait_to_skol_substs);
// Normalize the associated types in the trait_bounds.
let trait_bounds = trait_m.predicates.instantiate(tcx, &trait_to_skol_substs);
// Obtain the predicate split predicate sets for each.
let trait_pred = trait_bounds.predicates.split();
let impl_pred = impl_bounds.predicates.split();
// Obtain the predicate split predicate sets for each.
let trait_pred = trait_bounds.predicates.split();
let impl_pred = impl_bounds.predicates.split();
// This is the only tricky bit of the new way we check implementation methods
// We need to build a set of predicates where only the FnSpace bounds
// are from the trait and we assume all other bounds from the implementation
// to be previously satisfied.
//
// We then register the obligations from the impl_m and check to see
// if all constraints hold.
let hybrid_preds = VecPerParamSpace::new(
impl_pred.types,
impl_pred.selfs,
trait_pred.fns
);
// This is the only tricky bit of the new way we check implementation methods
// We need to build a set of predicates where only the FnSpace bounds
// are from the trait and we assume all other bounds from the implementation
// to be previously satisfied.
//
// We then register the obligations from the impl_m and check to see
// if all constraints hold.
let hybrid_preds = VecPerParamSpace::new(
impl_pred.types,
impl_pred.selfs,
trait_pred.fns
);
// Construct trait parameter environment and then shift it into the skolemized viewpoint.
// The key step here is to update the caller_bounds's predicates to be
// the new hybrid bounds we computed.
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id);
let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.into_vec());
let trait_param_env = traits::normalize_param_env_or_error(tcx,
trait_param_env,
normalize_cause.clone());
// FIXME(@jroesch) this seems ugly, but is a temporary change
infcx.parameter_environment = trait_param_env;
// Construct trait parameter environment and then shift it into the skolemized viewpoint.
// The key step here is to update the caller_bounds's predicates to be
// the new hybrid bounds we computed.
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id);
let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.into_vec());
let trait_param_env = traits::normalize_param_env_or_error(tcx,
trait_param_env,
normalize_cause.clone());
// FIXME(@jroesch) this seems ugly, but is a temporary change
infcx.parameter_environment = trait_param_env;
debug!("compare_impl_method: trait_bounds={:?}",
infcx.parameter_environment.caller_bounds);
debug!("compare_impl_method: trait_bounds={:?}",
infcx.parameter_environment.caller_bounds);
let mut selcx = traits::SelectionContext::new(&infcx);
let mut selcx = traits::SelectionContext::new(&infcx);
for predicate in impl_pred.fns {
let traits::Normalized { value: predicate, .. } =
traits::normalize(&mut selcx, normalize_cause.clone(), &predicate);
for predicate in impl_pred.fns {
let traits::Normalized { value: predicate, .. } =
traits::normalize(&mut selcx, normalize_cause.clone(), &predicate);
let cause = traits::ObligationCause {
span: impl_m_span,
body_id: impl_m_body_id,
code: traits::ObligationCauseCode::CompareImplMethodObligation
};
let cause = traits::ObligationCause {
span: impl_m_span,
body_id: impl_m_body_id,
code: traits::ObligationCauseCode::CompareImplMethodObligation
};
fulfillment_cx.register_predicate_obligation(
&infcx,
traits::Obligation::new(cause, predicate));
}
// We now need to check that the signature of the impl method is
// compatible with that of the trait method. We do this by
// checking that `impl_fty <: trait_fty`.
//
// FIXME. Unfortunately, this doesn't quite work right now because
// associated type normalization is not integrated into subtype
// checks. For the comparison to be valid, we need to
// normalize the associated types in the impl/trait methods
// first. However, because function types bind regions, just
// calling `normalize_associated_types_in` would have no effect on
// any associated types appearing in the fn arguments or return
// type.
// Compute skolemized form of impl and trait method tys.
let impl_fty = tcx.mk_fn_ptr(impl_m.fty.clone());
let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs);
let trait_fty = tcx.mk_fn_ptr(trait_m.fty.clone());
let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
let err = infcx.commit_if_ok(|snapshot| {
let origin = TypeOrigin::MethodCompatCheck(impl_m_span);
let (impl_sig, _) =
infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
infer::HigherRankedType,
&impl_m.fty.sig);
let impl_sig =
impl_sig.subst(tcx, impl_to_skol_substs);
let impl_sig =
assoc::normalize_associated_types_in(&infcx,
&mut fulfillment_cx,
impl_m_span,
impl_m_body_id,
&impl_sig);
let impl_fty = tcx.mk_fn_ptr(ty::BareFnTy {
unsafety: impl_m.fty.unsafety,
abi: impl_m.fty.abi,
sig: ty::Binder(impl_sig)
});
debug!("compare_impl_method: impl_fty={:?}",
impl_fty);
let (trait_sig, skol_map) =
infcx.skolemize_late_bound_regions(&trait_m.fty.sig, snapshot);
let trait_sig =
trait_sig.subst(tcx, &trait_to_skol_substs);
let trait_sig =
assoc::normalize_associated_types_in(&infcx,
&mut fulfillment_cx,
impl_m_span,
impl_m_body_id,
&trait_sig);
let trait_fty = tcx.mk_fn_ptr(ty::BareFnTy {
unsafety: trait_m.fty.unsafety,
abi: trait_m.fty.abi,
sig: ty::Binder(trait_sig)
});
debug!("compare_impl_method: trait_fty={:?}",
trait_fty);
infcx.sub_types(false, origin, impl_fty, trait_fty)?;
infcx.leak_check(false, &skol_map, snapshot)
});
match err {
Ok(()) => { }
Err(terr) => {
debug!("checking trait method for compatibility: impl ty {:?}, trait ty {:?}",
impl_fty,
trait_fty);
span_err!(tcx.sess, impl_m_span, E0053,
"method `{}` has an incompatible type for trait: {}",
trait_m.name,
terr);
return;
fulfillment_cx.register_predicate_obligation(
&infcx,
traits::Obligation::new(cause, predicate));
}
}
// Check that all obligations are satisfied by the implementation's
// version.
match fulfillment_cx.select_all_or_error(&infcx) {
Err(ref errors) => { infcx.report_fulfillment_errors(errors) }
Ok(_) => {}
}
// We now need to check that the signature of the impl method is
// compatible with that of the trait method. We do this by
// checking that `impl_fty <: trait_fty`.
//
// FIXME. Unfortunately, this doesn't quite work right now because
// associated type normalization is not integrated into subtype
// checks. For the comparison to be valid, we need to
// normalize the associated types in the impl/trait methods
// first. However, because function types bind regions, just
// calling `normalize_associated_types_in` would have no effect on
// any associated types appearing in the fn arguments or return
// type.
// Finally, resolve all regions. This catches wily misuses of
// lifetime parameters. We have to build up a plausible lifetime
// environment based on what we find in the trait. We could also
// include the obligations derived from the method argument types,
// but I don't think it's necessary -- after all, those are still
// in effect when type-checking the body, and all the
// where-clauses in the header etc should be implied by the trait
// anyway, so it shouldn't be needed there either. Anyway, we can
// always add more relations later (it's backwards compat).
let mut free_regions = FreeRegionMap::new();
free_regions.relate_free_regions_from_predicates(&infcx.parameter_environment.caller_bounds);
// Compute skolemized form of impl and trait method tys.
let impl_fty = tcx.mk_fn_ptr(impl_m.fty.clone());
let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs);
let trait_fty = tcx.mk_fn_ptr(trait_m.fty.clone());
let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id);
let err = infcx.commit_if_ok(|snapshot| {
let origin = TypeOrigin::MethodCompatCheck(impl_m_span);
let (impl_sig, _) =
infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
infer::HigherRankedType,
&impl_m.fty.sig);
let impl_sig =
impl_sig.subst(tcx, impl_to_skol_substs);
let impl_sig =
assoc::normalize_associated_types_in(&infcx,
&mut fulfillment_cx,
impl_m_span,
impl_m_body_id,
&impl_sig);
let impl_fty = tcx.mk_fn_ptr(ty::BareFnTy {
unsafety: impl_m.fty.unsafety,
abi: impl_m.fty.abi,
sig: ty::Binder(impl_sig)
});
debug!("compare_impl_method: impl_fty={:?}",
impl_fty);
let (trait_sig, skol_map) =
infcx.skolemize_late_bound_regions(&trait_m.fty.sig, snapshot);
let trait_sig =
trait_sig.subst(tcx, &trait_to_skol_substs);
let trait_sig =
assoc::normalize_associated_types_in(&infcx,
&mut fulfillment_cx,
impl_m_span,
impl_m_body_id,
&trait_sig);
let trait_fty = tcx.mk_fn_ptr(ty::BareFnTy {
unsafety: trait_m.fty.unsafety,
abi: trait_m.fty.abi,
sig: ty::Binder(trait_sig)
});
debug!("compare_impl_method: trait_fty={:?}",
trait_fty);
infcx.sub_types(false, origin, impl_fty, trait_fty)?;
infcx.leak_check(false, &skol_map, snapshot)
});
match err {
Ok(()) => { }
Err(terr) => {
debug!("checking trait method for compatibility: impl ty {:?}, trait ty {:?}",
impl_fty,
trait_fty);
span_err!(tcx.sess, impl_m_span, E0053,
"method `{}` has an incompatible type for trait: {}",
trait_m.name,
terr);
return;
}
}
// Check that all obligations are satisfied by the implementation's
// version.
match fulfillment_cx.select_all_or_error(&infcx) {
Err(ref errors) => { infcx.report_fulfillment_errors(errors) }
Ok(_) => {}
}
// Finally, resolve all regions. This catches wily misuses of
// lifetime parameters. We have to build up a plausible lifetime
// environment based on what we find in the trait. We could also
// include the obligations derived from the method argument types,
// but I don't think it's necessary -- after all, those are still
// in effect when type-checking the body, and all the
// where-clauses in the header etc should be implied by the trait
// anyway, so it shouldn't be needed there either. Anyway, we can
// always add more relations later (it's backwards compat).
let mut free_regions = FreeRegionMap::new();
free_regions.relate_free_regions_from_predicates(
&infcx.parameter_environment.caller_bounds);
infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id);
});
fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
span: Span,
@ -419,70 +421,69 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
impl_trait_ref);
let tcx = ccx.tcx;
let infcx = InferCtxt::new(tcx, &tcx.tables, None, ProjectionMode::AnyFinal);
let mut fulfillment_cx = traits::FulfillmentContext::new();
InferCtxt::enter(tcx, None, None, ProjectionMode::AnyFinal, |infcx| {
let mut fulfillment_cx = traits::FulfillmentContext::new();
// The below is for the most part highly similar to the procedure
// for methods above. It is simpler in many respects, especially
// because we shouldn't really have to deal with lifetimes or
// predicates. In fact some of this should probably be put into
// shared functions because of DRY violations...
let trait_to_impl_substs = &impl_trait_ref.substs;
// The below is for the most part highly similar to the procedure
// for methods above. It is simpler in many respects, especially
// because we shouldn't really have to deal with lifetimes or
// predicates. In fact some of this should probably be put into
// shared functions because of DRY violations...
let trait_to_impl_substs = &impl_trait_ref.substs;
// Create a parameter environment that represents the implementation's
// method.
let impl_c_node_id = tcx.map.as_local_node_id(impl_c.def_id).unwrap();
let impl_param_env = ty::ParameterEnvironment::for_item(tcx, impl_c_node_id);
// Create a parameter environment that represents the implementation's
// method.
let impl_c_node_id = tcx.map.as_local_node_id(impl_c.def_id).unwrap();
let impl_param_env = ty::ParameterEnvironment::for_item(tcx, impl_c_node_id);
// Create mapping from impl to skolemized.
let impl_to_skol_substs = &impl_param_env.free_substs;
// Create mapping from impl to skolemized.
let impl_to_skol_substs = &impl_param_env.free_substs;
// Create mapping from trait to skolemized.
let trait_to_skol_substs =
trait_to_impl_substs
.subst(tcx, impl_to_skol_substs)
.with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
impl_to_skol_substs.regions.get_slice(subst::FnSpace).to_vec());
debug!("compare_const_impl: trait_to_skol_substs={:?}",
trait_to_skol_substs);
// Create mapping from trait to skolemized.
let trait_to_skol_substs =
trait_to_impl_substs
.subst(tcx, impl_to_skol_substs)
.with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
impl_to_skol_substs.regions.get_slice(subst::FnSpace).to_vec());
debug!("compare_const_impl: trait_to_skol_substs={:?}",
trait_to_skol_substs);
// Compute skolemized form of impl and trait const tys.
let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
let trait_ty = trait_c.ty.subst(tcx, &trait_to_skol_substs);
// Compute skolemized form of impl and trait const tys.
let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
let trait_ty = trait_c.ty.subst(tcx, &trait_to_skol_substs);
let err = infcx.commit_if_ok(|_| {
let origin = TypeOrigin::Misc(impl_c_span);
let err = infcx.commit_if_ok(|_| {
let origin = TypeOrigin::Misc(impl_c_span);
// There is no "body" here, so just pass dummy id.
let impl_ty =
assoc::normalize_associated_types_in(&infcx,
&mut fulfillment_cx,
impl_c_span,
0,
&impl_ty);
// There is no "body" here, so just pass dummy id.
let impl_ty =
assoc::normalize_associated_types_in(&infcx,
&mut fulfillment_cx,
impl_c_span,
0,
&impl_ty);
debug!("compare_const_impl: impl_ty={:?}",
impl_ty);
debug!("compare_const_impl: impl_ty={:?}",
impl_ty);
let trait_ty =
assoc::normalize_associated_types_in(&infcx,
&mut fulfillment_cx,
impl_c_span,
0,
&trait_ty);
let trait_ty =
assoc::normalize_associated_types_in(&infcx,
&mut fulfillment_cx,
impl_c_span,
0,
&trait_ty);
debug!("compare_const_impl: trait_ty={:?}",
trait_ty);
debug!("compare_const_impl: trait_ty={:?}",
trait_ty);
infcx.sub_types(false, origin, impl_ty, trait_ty)
});
infcx.sub_types(false, origin, impl_ty, trait_ty)
.map(|InferOk { obligations, .. }| {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty())
})
});
match err {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty())
}
Err(terr) => {
if let Err(terr) = err {
debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
impl_ty,
trait_ty);
@ -491,7 +492,6 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
trait: {}",
trait_c.name,
terr);
return;
}
}
});
}

View File

@ -84,43 +84,43 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
// check that the impl type can be made to match the trait type.
let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id);
let infcx = InferCtxt::new(tcx, &tcx.tables, Some(impl_param_env),
ProjectionMode::AnyFinal);
let mut fulfillment_cx = traits::FulfillmentContext::new();
InferCtxt::enter(tcx, None, Some(impl_param_env), ProjectionMode::AnyFinal, |infcx| {
let mut fulfillment_cx = traits::FulfillmentContext::new();
let named_type = tcx.lookup_item_type(self_type_did).ty;
let named_type = named_type.subst(tcx, &infcx.parameter_environment.free_substs);
let named_type = tcx.lookup_item_type(self_type_did).ty;
let named_type = named_type.subst(tcx, &infcx.parameter_environment.free_substs);
let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
let fresh_impl_substs =
infcx.fresh_substs_for_generics(drop_impl_span, drop_impl_generics);
let fresh_impl_self_ty = drop_impl_ty.subst(tcx, &fresh_impl_substs);
let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
let fresh_impl_substs =
infcx.fresh_substs_for_generics(drop_impl_span, drop_impl_generics);
let fresh_impl_self_ty = drop_impl_ty.subst(tcx, &fresh_impl_substs);
if let Err(_) = infcx.eq_types(true, infer::TypeOrigin::Misc(drop_impl_span),
named_type, fresh_impl_self_ty) {
let item_span = tcx.map.span(self_type_node_id);
struct_span_err!(tcx.sess, drop_impl_span, E0366,
"Implementations of Drop cannot be specialized")
.span_note(item_span,
"Use same sequence of generic type and region \
parameters that is on the struct/enum definition")
.emit();
return Err(());
}
if let Err(_) = infcx.eq_types(true, infer::TypeOrigin::Misc(drop_impl_span),
named_type, fresh_impl_self_ty) {
let item_span = tcx.map.span(self_type_node_id);
struct_span_err!(tcx.sess, drop_impl_span, E0366,
"Implementations of Drop cannot be specialized")
.span_note(item_span,
"Use same sequence of generic type and region \
parameters that is on the struct/enum definition")
.emit();
return Err(());
}
if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
// this could be reached when we get lazy normalization
infcx.report_fulfillment_errors(errors);
return Err(());
}
if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
// this could be reached when we get lazy normalization
infcx.report_fulfillment_errors(errors);
return Err(());
}
if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) {
infcx.report_fulfillment_errors_as_warnings(errors, drop_impl_node_id);
}
let free_regions = FreeRegionMap::new();
infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_node_id);
Ok(())
let free_regions = FreeRegionMap::new();
infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_node_id);
Ok(())
})
}
/// Confirms that every predicate imposed by dtor_predicates is

View File

@ -373,22 +373,25 @@ impl<'a, 'gcx, 'tcx> Deref for FnCtxt<'a, 'gcx, 'tcx> {
}
impl<'a, 'tcx> Inherited<'a, 'tcx, 'tcx> {
fn new(ccx: &'a CrateCtxt<'a, 'tcx>,
tables: &'a RefCell<ty::Tables<'tcx>>,
param_env: ty::ParameterEnvironment<'tcx>)
-> Inherited<'a, 'tcx, 'tcx> {
Inherited {
ccx: ccx,
infcx: InferCtxt::new(ccx.tcx,
tables,
Some(param_env),
ProjectionMode::AnyFinal),
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
locals: RefCell::new(NodeMap()),
deferred_call_resolutions: RefCell::new(DefIdMap()),
deferred_cast_checks: RefCell::new(Vec::new()),
}
fn enter<F, R>(ccx: &'a CrateCtxt<'a, 'tcx>,
param_env: ty::ParameterEnvironment<'tcx>,
f: F) -> R
where F: for<'b> FnOnce(Inherited<'b, 'tcx, 'tcx>) -> R
{
InferCtxt::enter(ccx.tcx,
Some(ty::Tables::empty()),
Some(param_env),
ProjectionMode::AnyFinal,
|infcx| {
f(Inherited {
ccx: ccx,
infcx: infcx,
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
locals: RefCell::new(NodeMap()),
deferred_call_resolutions: RefCell::new(DefIdMap()),
deferred_cast_checks: RefCell::new(Vec::new()),
})
})
}
fn normalize_associated_types_in<T>(&self,
@ -407,15 +410,6 @@ impl<'a, 'tcx> Inherited<'a, 'tcx, 'tcx> {
}
fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
tables: &'a RefCell<ty::Tables<'tcx>>)
-> Inherited<'a, 'tcx, 'tcx> {
// It's kind of a kludge to manufacture a fake function context
// and statement context, but we might as well do write the code only once
let param_env = ccx.tcx.empty_parameter_environment();
Inherited::new(ccx, &tables, param_env)
}
struct CheckItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
struct CheckItemBodiesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
@ -492,36 +486,33 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
raw_fty: Ty<'tcx>,
param_env: ty::ParameterEnvironment<'tcx>)
{
match raw_fty.sty {
ty::TyFnDef(_, _, ref fn_ty) => {
let tables = RefCell::new(ty::Tables::empty());
let inh = Inherited::new(ccx, &tables, param_env);
// Compute the fty from point of view of inside fn.
let fn_scope = ccx.tcx.region_maps.call_site_extent(fn_id, body.id);
let fn_sig =
fn_ty.sig.subst(ccx.tcx, &inh.parameter_environment.free_substs);
let fn_sig =
ccx.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
let fn_sig =
inh.normalize_associated_types_in(body.span,
body.id,
&fn_sig);
let fcx = check_fn(ccx, fn_ty.unsafety, fn_id, &fn_sig,
decl, fn_id, body, &inh);
fcx.select_all_obligations_and_apply_defaults();
fcx.closure_analyze_fn(body);
fcx.select_obligations_where_possible();
fcx.check_casts();
fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
fcx.regionck_fn(fn_id, fn_span, decl, body);
fcx.resolve_type_vars_in_fn(decl, body);
}
let fn_ty = match raw_fty.sty {
ty::TyFnDef(_, _, f) => f,
_ => span_bug!(body.span, "check_bare_fn: function type expected")
}
};
Inherited::enter(ccx, param_env, |inh| {
// Compute the fty from point of view of inside fn.
let fn_scope = ccx.tcx.region_maps.call_site_extent(fn_id, body.id);
let fn_sig =
fn_ty.sig.subst(ccx.tcx, &inh.parameter_environment.free_substs);
let fn_sig =
ccx.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
let fn_sig =
inh.normalize_associated_types_in(body.span, body.id, &fn_sig);
let fcx = check_fn(ccx, fn_ty.unsafety, fn_id, &fn_sig,
decl, fn_id, body, &inh);
fcx.select_all_obligations_and_apply_defaults();
fcx.closure_analyze_fn(body);
fcx.select_obligations_where_possible();
fcx.check_casts();
fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
fcx.regionck_fn(fn_id, fn_span, decl, body);
fcx.resolve_type_vars_in_fn(decl, body);
});
}
struct GatherLocalsVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
@ -1135,22 +1126,22 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
fn check_const_in_type<'a,'tcx>(ccx: &'a CrateCtxt<'a,'tcx>,
expr: &'tcx hir::Expr,
expected_type: Ty<'tcx>) {
let tables = RefCell::new(ty::Tables::empty());
let inh = static_inherited_fields(ccx, &tables);
let fcx = FnCtxt::new(&inh, ty::FnConverging(expected_type), expr.id);
fcx.check_const_with_ty(expr.span, expr, expected_type);
Inherited::enter(ccx, ccx.tcx.empty_parameter_environment(), |inh| {
let fcx = FnCtxt::new(&inh, ty::FnConverging(expected_type), expr.id);
fcx.check_const_with_ty(expr.span, expr, expected_type);
});
}
fn check_const<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
sp: Span,
e: &'tcx hir::Expr,
id: ast::NodeId) {
let tables = RefCell::new(ty::Tables::empty());
let inh = static_inherited_fields(ccx, &tables);
let rty = ccx.tcx.node_id_to_type(id);
let fcx = FnCtxt::new(&inh, ty::FnConverging(rty), e.id);
let declty = fcx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(id)).ty;
fcx.check_const_with_ty(sp, e, declty);
Inherited::enter(ccx, ccx.tcx.empty_parameter_environment(), |inh| {
let rty = ccx.tcx.node_id_to_type(id);
let fcx = FnCtxt::new(&inh, ty::FnConverging(rty), e.id);
let declty = fcx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(id)).ty;
fcx.check_const_with_ty(sp, e, declty);
});
}
/// Checks whether a type can be represented in memory. In particular, it
@ -1206,21 +1197,21 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, id: ast::Node
}
}
#[allow(trivial_numeric_casts)]
pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
sp: Span,
vs: &'tcx [hir::Variant],
id: ast::NodeId) {
fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
vs: &'tcx [hir::Variant],
id: ast::NodeId,
hint: attr::ReprAttr) {
#![allow(trivial_numeric_casts)]
let def_id = ccx.tcx.map.local_def_id(id);
let hint = *ccx.tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny);
if hint != attr::ReprAny && vs.is_empty() {
span_err!(ccx.tcx.sess, sp, E0084,
"unsupported representation for zero-variant enum");
}
Inherited::enter(ccx, ccx.tcx.empty_parameter_environment(), |inh| {
let rty = ccx.tcx.node_id_to_type(id);
let mut disr_vals: Vec<ty::Disr> = Vec::new();
let tables = RefCell::new(ty::Tables::empty());
let inh = static_inherited_fields(ccx, &tables);
let fcx = FnCtxt::new(&inh, ty::FnConverging(rty), id);
let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx);
@ -1233,34 +1224,22 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
let def_id = ccx.tcx.map.local_def_id(id);
let variants = &ccx.tcx.lookup_adt_def(def_id).variants;
let mut disr_vals: Vec<ty::Disr> = Vec::new();
for (v, variant) in vs.iter().zip(variants.iter()) {
let current_disr_val = variant.disr_val;
// Check for duplicate discriminant values
match disr_vals.iter().position(|&x| x == current_disr_val) {
Some(i) => {
let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0081,
"discriminant value `{}` already exists", disr_vals[i]);
let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap();
span_note!(&mut err, ccx.tcx.map.span(variant_i_node_id),
"conflicting discriminant here");
err.emit();
}
None => {}
if let Some(i) = disr_vals.iter().position(|&x| x == current_disr_val) {
let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0081,
"discriminant value `{}` already exists", disr_vals[i]);
let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap();
span_note!(&mut err, ccx.tcx.map.span(variant_i_node_id),
"conflicting discriminant here");
err.emit();
}
disr_vals.push(current_disr_val);
}
}
let def_id = ccx.tcx.map.local_def_id(id);
let hint = *ccx.tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny);
if hint != attr::ReprAny && vs.is_empty() {
span_err!(ccx.tcx.sess, sp, E0084,
"unsupported representation for zero-variant enum");
}
do_check(ccx, vs, id, hint);
});
check_representable(ccx.tcx, sp, id, "enum");
}

View File

@ -17,7 +17,6 @@ use rustc::ty::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace};
use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt};
use std::cell::RefCell;
use std::collections::HashSet;
use syntax::ast;
use syntax::codemap::{Span};
@ -180,12 +179,12 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
{
let ccx = self.ccx;
let param_env = ty::ParameterEnvironment::for_item(ccx.tcx, id);
let tables = RefCell::new(ty::Tables::empty());
let inh = Inherited::new(ccx, &tables, param_env);
let fcx = FnCtxt::new(&inh, ty::FnDiverging, id);
let wf_tys = f(&fcx, self);
fcx.select_all_obligations_or_error();
fcx.regionck_item(id, span, &wf_tys);
Inherited::enter(ccx, param_env, |inh| {
let fcx = FnCtxt::new(&inh, ty::FnDiverging, id);
let wf_tys = f(&fcx, self);
fcx.select_all_obligations_or_error();
fcx.regionck_item(id, span, &wf_tys);
});
}
/// In a type definition, we check that to ensure that the types of the fields are well-formed.

View File

@ -376,111 +376,111 @@ fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
source, target);
let infcx = InferCtxt::new(tcx, &tcx.tables, Some(param_env), ProjectionMode::Topmost);
InferCtxt::enter(tcx, None, Some(param_env), ProjectionMode::Topmost, |infcx| {
let origin = TypeOrigin::Misc(span);
let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>,
mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| {
if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
infcx.report_mismatched_types(origin, mk_ptr(mt_b.ty),
target, ty::error::TypeError::Mutability);
}
(mt_a.ty, mt_b.ty, unsize_trait, None)
};
let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) {
(&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None),
let origin = TypeOrigin::Misc(span);
let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>,
mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| {
if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
infcx.report_mismatched_types(origin, mk_ptr(mt_b.ty),
target, ty::error::TypeError::Mutability);
}
(mt_a.ty, mt_b.ty, unsize_trait, None)
};
let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) {
(&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None),
(&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => {
infcx.sub_regions(infer::RelateObjectBound(span), *r_b, *r_a);
check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
}
(&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) |
(&ty::TyRawPtr(mt_a), &ty::TyRawPtr(mt_b)) => {
check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
}
(&ty::TyStruct(def_a, substs_a), &ty::TyStruct(def_b, substs_b)) => {
if def_a != def_b {
let source_path = tcx.item_path_str(def_a.did);
let target_path = tcx.item_path_str(def_b.did);
span_err!(tcx.sess, span, E0377,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures with the same \
definition; expected {}, found {}",
source_path, target_path);
return;
(&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => {
infcx.sub_regions(infer::RelateObjectBound(span), *r_b, *r_a);
check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
}
let fields = &def_a.struct_variant().fields;
let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| {
let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
(&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) |
(&ty::TyRawPtr(mt_a), &ty::TyRawPtr(mt_b)) => {
check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
}
if f.unsubst_ty().is_phantom_data() {
// Ignore PhantomData fields
None
} else if infcx.sub_types(false, origin, b, a).is_ok() {
// Ignore fields that aren't significantly changed
None
} else {
// Collect up all fields that were significantly changed
// i.e. those that contain T in coerce_unsized T -> U
Some((i, a, b))
(&ty::TyStruct(def_a, substs_a), &ty::TyStruct(def_b, substs_b)) => {
if def_a != def_b {
let source_path = tcx.item_path_str(def_a.did);
let target_path = tcx.item_path_str(def_b.did);
span_err!(tcx.sess, span, E0377,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures with the same \
definition; expected {}, found {}",
source_path, target_path);
return;
}
}).collect::<Vec<_>>();
if diff_fields.is_empty() {
span_err!(tcx.sess, span, E0374,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures with one field \
being coerced, none found");
return;
} else if diff_fields.len() > 1 {
span_err!(tcx.sess, span, E0375,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures with one field \
being coerced, but {} fields need coercions: {}",
diff_fields.len(), diff_fields.iter().map(|&(i, a, b)| {
format!("{} ({} to {})", fields[i].name, a, b)
}).collect::<Vec<_>>().join(", "));
return;
let fields = &def_a.struct_variant().fields;
let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| {
let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
if f.unsubst_ty().is_phantom_data() {
// Ignore PhantomData fields
None
} else if infcx.sub_types(false, origin, b, a).is_ok() {
// Ignore fields that aren't significantly changed
None
} else {
// Collect up all fields that were significantly changed
// i.e. those that contain T in coerce_unsized T -> U
Some((i, a, b))
}
}).collect::<Vec<_>>();
if diff_fields.is_empty() {
span_err!(tcx.sess, span, E0374,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures with one field \
being coerced, none found");
return;
} else if diff_fields.len() > 1 {
span_err!(tcx.sess, span, E0375,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures with one field \
being coerced, but {} fields need coercions: {}",
diff_fields.len(), diff_fields.iter().map(|&(i, a, b)| {
format!("{} ({} to {})", fields[i].name, a, b)
}).collect::<Vec<_>>().join(", "));
return;
}
let (i, a, b) = diff_fields[0];
let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
(a, b, coerce_unsized_trait, Some(kind))
}
let (i, a, b) = diff_fields[0];
let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
(a, b, coerce_unsized_trait, Some(kind))
_ => {
span_err!(tcx.sess, span, E0376,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures");
return;
}
};
let mut fulfill_cx = traits::FulfillmentContext::new();
// Register an obligation for `A: Trait<B>`.
let cause = traits::ObligationCause::misc(span, impl_node_id);
let predicate = tcx.predicate_for_trait_def(cause, trait_def_id, 0,
source, vec![target]);
fulfill_cx.register_predicate_obligation(&infcx, predicate);
// Check that all transitive obligations are satisfied.
if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
infcx.report_fulfillment_errors(&errors);
}
_ => {
span_err!(tcx.sess, span, E0376,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures");
return;
// Finally, resolve all regions.
let mut free_regions = FreeRegionMap::new();
free_regions.relate_free_regions_from_predicates(
&infcx.parameter_environment.caller_bounds);
infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
if let Some(kind) = kind {
tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
}
};
let mut fulfill_cx = traits::FulfillmentContext::new();
// Register an obligation for `A: Trait<B>`.
let cause = traits::ObligationCause::misc(span, impl_node_id);
let predicate = tcx.predicate_for_trait_def(cause, trait_def_id, 0,
source, vec![target]);
fulfill_cx.register_predicate_obligation(&infcx, predicate);
// Check that all transitive obligations are satisfied.
if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
infcx.report_fulfillment_errors(&errors);
}
// Finally, resolve all regions.
let mut free_regions = FreeRegionMap::new();
free_regions.relate_free_regions_from_predicates(&infcx.parameter_environment
.caller_bounds);
infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
if let Some(kind) = kind {
tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
}
});
});
}
}
@ -511,18 +511,16 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
err.emit();
}
pub fn check_coherence(crate_context: &CrateCtxt) {
let _task = crate_context.tcx.dep_graph.in_task(DepNode::Coherence);
let infcx = InferCtxt::new(crate_context.tcx,
&crate_context.tcx.tables,
None,
ProjectionMode::Topmost);
CoherenceChecker {
crate_context: crate_context,
inference_context: infcx,
inherent_impls: RefCell::new(FnvHashMap()),
}.check();
unsafety::check(crate_context.tcx);
orphan::check(crate_context.tcx);
overlap::check(crate_context.tcx);
pub fn check_coherence(ccx: &CrateCtxt) {
let _task = ccx.tcx.dep_graph.in_task(DepNode::Coherence);
InferCtxt::enter(ccx.tcx, None, None, ProjectionMode::Topmost, |infcx| {
CoherenceChecker {
crate_context: ccx,
inference_context: infcx,
inherent_impls: RefCell::new(FnvHashMap()),
}.check();
});
unsafety::check(ccx.tcx);
orphan::check(ccx.tcx);
overlap::check(ccx.tcx);
}

View File

@ -85,11 +85,11 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
for (i, &impl1_def_id) in impls.iter().enumerate() {
for &impl2_def_id in &impls[(i+1)..] {
let infcx = InferCtxt::new(self.tcx, &self.tcx.tables, None,
ProjectionMode::Topmost);
if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
}
InferCtxt::enter(self.tcx, None, None, ProjectionMode::Topmost, |infcx| {
if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
}
});
}
}
}
@ -138,24 +138,12 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
// insertion failed due to overlap
if let Err(overlap) = insert_result {
// only print the Self type if it has at least some outer
// concrete shell; otherwise, it's not adding much
// information.
let self_type = {
overlap.on_trait_ref.substs.self_ty().and_then(|ty| {
if ty.has_concrete_skeleton() {
Some(format!(" for type `{}`", ty))
} else {
None
}
}).unwrap_or(String::new())
};
let mut err = struct_span_err!(
self.tcx.sess, self.tcx.span_of_impl(impl_def_id).unwrap(), E0119,
"conflicting implementations of trait `{}`{}:",
overlap.on_trait_ref,
self_type);
overlap.trait_desc,
overlap.self_desc.map_or(String::new(),
|ty| format!(" for type `{}`", ty)));
match self.tcx.span_of_impl(overlap.with_impl) {
Ok(span) => {

View File

@ -203,8 +203,9 @@ fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let err = if let Some(infcx) = maybe_infcx {
infcx.eq_types(false, TypeOrigin::Misc(span), t1, t2).err()
} else {
let infcx = InferCtxt::new(ccx.tcx, &ccx.tcx.tables, None, ProjectionMode::AnyFinal);
infcx.eq_types(false, TypeOrigin::Misc(span), t1, t2).err()
InferCtxt::enter(ccx.tcx, None, None, ProjectionMode::AnyFinal, |infcx| {
infcx.eq_types(false, TypeOrigin::Misc(span), t1, t2).err()
})
};
if let Some(ref terr) = err {