Run rustfmt on librustc_typeck/check/ folder
This commit is contained in:
parent
75c155b834
commit
4ef3f59188
7 changed files with 627 additions and 597 deletions
|
@ -9,13 +9,13 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use rustc::infer::InferCtxt;
|
use rustc::infer::InferCtxt;
|
||||||
use rustc::traits::{self, FulfillmentContext, Normalized, MiscObligation,
|
use rustc::traits::{self, FulfillmentContext, Normalized, MiscObligation, SelectionContext,
|
||||||
SelectionContext, ObligationCause};
|
ObligationCause};
|
||||||
use rustc::ty::fold::TypeFoldable;
|
use rustc::ty::fold::TypeFoldable;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
|
||||||
//FIXME(@jroesch): Ideally we should be able to drop the fulfillment_cx argument.
|
// FIXME(@jroesch): Ideally we should be able to drop the fulfillment_cx argument.
|
||||||
pub fn normalize_associated_types_in<'a, 'gcx, 'tcx, T>(
|
pub fn normalize_associated_types_in<'a, 'gcx, 'tcx, T>(
|
||||||
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||||
fulfillment_cx: &mut FulfillmentContext<'tcx>,
|
fulfillment_cx: &mut FulfillmentContext<'tcx>,
|
||||||
|
|
|
@ -26,7 +26,7 @@ use syntax::parse::token;
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
enum AutoderefKind {
|
enum AutoderefKind {
|
||||||
Builtin,
|
Builtin,
|
||||||
Overloaded
|
Overloaded,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||||
|
@ -35,7 +35,7 @@ pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||||
cur_ty: Ty<'tcx>,
|
cur_ty: Ty<'tcx>,
|
||||||
obligations: Vec<traits::PredicateObligation<'tcx>>,
|
obligations: Vec<traits::PredicateObligation<'tcx>>,
|
||||||
at_start: bool,
|
at_start: bool,
|
||||||
span: Span
|
span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
|
||||||
|
@ -45,7 +45,8 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
|
||||||
let tcx = self.fcx.tcx;
|
let tcx = self.fcx.tcx;
|
||||||
|
|
||||||
debug!("autoderef: steps={:?}, cur_ty={:?}",
|
debug!("autoderef: steps={:?}, cur_ty={:?}",
|
||||||
self.steps, self.cur_ty);
|
self.steps,
|
||||||
|
self.cur_ty);
|
||||||
if self.at_start {
|
if self.at_start {
|
||||||
self.at_start = false;
|
self.at_start = false;
|
||||||
debug!("autoderef stage #0 is {:?}", self.cur_ty);
|
debug!("autoderef stage #0 is {:?}", self.cur_ty);
|
||||||
|
@ -54,11 +55,13 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
if self.steps.len() == tcx.sess.recursion_limit.get() {
|
if self.steps.len() == tcx.sess.recursion_limit.get() {
|
||||||
// We've reached the recursion limit, error gracefully.
|
// We've reached the recursion limit, error gracefully.
|
||||||
struct_span_err!(tcx.sess, self.span, E0055,
|
struct_span_err!(tcx.sess,
|
||||||
"reached the recursion limit while auto-dereferencing {:?}",
|
self.span,
|
||||||
self.cur_ty)
|
E0055,
|
||||||
.span_label(self.span, &format!("deref recursion limit reached"))
|
"reached the recursion limit while auto-dereferencing {:?}",
|
||||||
.emit();
|
self.cur_ty)
|
||||||
|
.span_label(self.span, &format!("deref recursion limit reached"))
|
||||||
|
.emit();
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +75,7 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
match self.overloaded_deref_ty(self.cur_ty) {
|
match self.overloaded_deref_ty(self.cur_ty) {
|
||||||
Some(ty) => (AutoderefKind::Overloaded, ty),
|
Some(ty) => (AutoderefKind::Overloaded, ty),
|
||||||
_ => return None
|
_ => return None,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -81,8 +84,10 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.steps.push((self.cur_ty, kind));
|
self.steps.push((self.cur_ty, kind));
|
||||||
debug!("autoderef stage #{:?} is {:?} from {:?}", self.steps.len(),
|
debug!("autoderef stage #{:?} is {:?} from {:?}",
|
||||||
new_ty, (self.cur_ty, kind));
|
self.steps.len(),
|
||||||
|
new_ty,
|
||||||
|
(self.cur_ty, kind));
|
||||||
self.cur_ty = new_ty;
|
self.cur_ty = new_ty;
|
||||||
|
|
||||||
Some((self.cur_ty, self.steps.len()))
|
Some((self.cur_ty, self.steps.len()))
|
||||||
|
@ -99,9 +104,9 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
|
||||||
let trait_ref = TraitRef {
|
let trait_ref = TraitRef {
|
||||||
def_id: match tcx.lang_items.deref_trait() {
|
def_id: match tcx.lang_items.deref_trait() {
|
||||||
Some(f) => f,
|
Some(f) => f,
|
||||||
None => return None
|
None => return None,
|
||||||
},
|
},
|
||||||
substs: Substs::new_trait(tcx, self.cur_ty, &[])
|
substs: Substs::new_trait(tcx, self.cur_ty, &[]),
|
||||||
};
|
};
|
||||||
|
|
||||||
let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
|
let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
|
||||||
|
@ -113,15 +118,13 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let normalized = traits::normalize_projection_type(
|
let normalized = traits::normalize_projection_type(&mut selcx,
|
||||||
&mut selcx,
|
ty::ProjectionTy {
|
||||||
ty::ProjectionTy {
|
trait_ref: trait_ref,
|
||||||
trait_ref: trait_ref,
|
item_name: token::intern("Target"),
|
||||||
item_name: token::intern("Target")
|
},
|
||||||
},
|
cause,
|
||||||
cause,
|
0);
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
debug!("overloaded_deref_ty({:?}) = {:?}", ty, normalized);
|
debug!("overloaded_deref_ty({:?}) = {:?}", ty, normalized);
|
||||||
self.obligations.extend(normalized.obligations);
|
self.obligations.extend(normalized.obligations);
|
||||||
|
@ -134,17 +137,23 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I)
|
pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I)
|
||||||
where I: IntoIterator<Item=&'b hir::Expr>
|
where I: IntoIterator<Item = &'b hir::Expr>
|
||||||
{
|
{
|
||||||
let methods : Vec<_> = self.steps.iter().map(|&(ty, kind)| {
|
let methods: Vec<_> = self.steps
|
||||||
if let AutoderefKind::Overloaded = kind {
|
.iter()
|
||||||
self.fcx.try_overloaded_deref(self.span, None, ty, pref)
|
.map(|&(ty, kind)| {
|
||||||
} else {
|
if let AutoderefKind::Overloaded = kind {
|
||||||
None
|
self.fcx.try_overloaded_deref(self.span, None, ty, pref)
|
||||||
}
|
} else {
|
||||||
}).collect();
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
debug!("finalize({:?}) - {:?},{:?}", pref, methods, self.obligations);
|
debug!("finalize({:?}) - {:?},{:?}",
|
||||||
|
pref,
|
||||||
|
methods,
|
||||||
|
self.obligations);
|
||||||
|
|
||||||
for expr in exprs {
|
for expr in exprs {
|
||||||
debug!("finalize - finalizing #{} - {:?}", expr.id, expr);
|
debug!("finalize - finalizing #{} - {:?}", expr.id, expr);
|
||||||
|
@ -163,18 +172,14 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
pub fn autoderef(&'a self,
|
pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx, 'tcx> {
|
||||||
span: Span,
|
|
||||||
base_ty: Ty<'tcx>)
|
|
||||||
-> Autoderef<'a, 'gcx, 'tcx>
|
|
||||||
{
|
|
||||||
Autoderef {
|
Autoderef {
|
||||||
fcx: self,
|
fcx: self,
|
||||||
steps: vec![],
|
steps: vec![],
|
||||||
cur_ty: self.resolve_type_vars_if_possible(&base_ty),
|
cur_ty: self.resolve_type_vars_if_possible(&base_ty),
|
||||||
obligations: vec![],
|
obligations: vec![],
|
||||||
at_start: true,
|
at_start: true,
|
||||||
span: span
|
span: span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,28 +188,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
base_expr: Option<&hir::Expr>,
|
base_expr: Option<&hir::Expr>,
|
||||||
base_ty: Ty<'tcx>,
|
base_ty: Ty<'tcx>,
|
||||||
lvalue_pref: LvaluePreference)
|
lvalue_pref: LvaluePreference)
|
||||||
-> Option<MethodCallee<'tcx>>
|
-> Option<MethodCallee<'tcx>> {
|
||||||
{
|
|
||||||
debug!("try_overloaded_deref({:?},{:?},{:?},{:?})",
|
debug!("try_overloaded_deref({:?},{:?},{:?},{:?})",
|
||||||
span, base_expr, base_ty, lvalue_pref);
|
span,
|
||||||
|
base_expr,
|
||||||
|
base_ty,
|
||||||
|
lvalue_pref);
|
||||||
// Try DerefMut first, if preferred.
|
// Try DerefMut first, if preferred.
|
||||||
let method = match (lvalue_pref, self.tcx.lang_items.deref_mut_trait()) {
|
let method = match (lvalue_pref, self.tcx.lang_items.deref_mut_trait()) {
|
||||||
(PreferMutLvalue, Some(trait_did)) => {
|
(PreferMutLvalue, Some(trait_did)) => {
|
||||||
self.lookup_method_in_trait(span, base_expr,
|
self.lookup_method_in_trait(span,
|
||||||
token::intern("deref_mut"), trait_did,
|
base_expr,
|
||||||
base_ty, None)
|
token::intern("deref_mut"),
|
||||||
|
trait_did,
|
||||||
|
base_ty,
|
||||||
|
None)
|
||||||
}
|
}
|
||||||
_ => None
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Otherwise, fall back to Deref.
|
// Otherwise, fall back to Deref.
|
||||||
let method = match (method, self.tcx.lang_items.deref_trait()) {
|
let method = match (method, self.tcx.lang_items.deref_trait()) {
|
||||||
(None, Some(trait_did)) => {
|
(None, Some(trait_did)) => {
|
||||||
self.lookup_method_in_trait(span, base_expr,
|
self.lookup_method_in_trait(span,
|
||||||
token::intern("deref"), trait_did,
|
base_expr,
|
||||||
base_ty, None)
|
token::intern("deref"),
|
||||||
|
trait_did,
|
||||||
|
base_ty,
|
||||||
|
None)
|
||||||
}
|
}
|
||||||
(method, _) => method
|
(method, _) => method,
|
||||||
};
|
};
|
||||||
|
|
||||||
method
|
method
|
||||||
|
|
|
@ -8,8 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use super::{DeferredCallResolution, Expectation, FnCtxt,
|
use super::{DeferredCallResolution, Expectation, FnCtxt, TupleArgumentsFlag};
|
||||||
TupleArgumentsFlag};
|
|
||||||
|
|
||||||
use CrateCtxt;
|
use CrateCtxt;
|
||||||
use hir::def::Def;
|
use hir::def::Def;
|
||||||
|
@ -27,7 +26,10 @@ use rustc::hir;
|
||||||
/// method that is called)
|
/// method that is called)
|
||||||
pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: DefId) {
|
pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: DefId) {
|
||||||
if ccx.tcx.lang_items.drop_trait() == Some(trait_id) {
|
if ccx.tcx.lang_items.drop_trait() == Some(trait_id) {
|
||||||
struct_span_err!(ccx.tcx.sess, span, E0040, "explicit use of destructor method")
|
struct_span_err!(ccx.tcx.sess,
|
||||||
|
span,
|
||||||
|
E0040,
|
||||||
|
"explicit use of destructor method")
|
||||||
.span_label(span, &format!("explicit destructor calls not allowed"))
|
.span_label(span, &format!("explicit destructor calls not allowed"))
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
@ -36,7 +38,7 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id:
|
||||||
enum CallStep<'tcx> {
|
enum CallStep<'tcx> {
|
||||||
Builtin,
|
Builtin,
|
||||||
DeferredClosure(ty::FnSig<'tcx>),
|
DeferredClosure(ty::FnSig<'tcx>),
|
||||||
Overloaded(ty::MethodCallee<'tcx>)
|
Overloaded(ty::MethodCallee<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
@ -44,15 +46,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
call_expr: &'gcx hir::Expr,
|
call_expr: &'gcx hir::Expr,
|
||||||
callee_expr: &'gcx hir::Expr,
|
callee_expr: &'gcx hir::Expr,
|
||||||
arg_exprs: &'gcx [P<hir::Expr>],
|
arg_exprs: &'gcx [P<hir::Expr>],
|
||||||
expected: Expectation<'tcx>) -> Ty<'tcx>
|
expected: Expectation<'tcx>)
|
||||||
{
|
-> Ty<'tcx> {
|
||||||
let original_callee_ty = self.check_expr(callee_expr);
|
let original_callee_ty = self.check_expr(callee_expr);
|
||||||
let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty);
|
let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty);
|
||||||
|
|
||||||
let mut autoderef = self.autoderef(callee_expr.span, expr_ty);
|
let mut autoderef = self.autoderef(callee_expr.span, expr_ty);
|
||||||
let result = autoderef.by_ref().flat_map(|(adj_ty, idx)| {
|
let result = autoderef.by_ref()
|
||||||
self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx)
|
.flat_map(|(adj_ty, idx)| {
|
||||||
}).next();
|
self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx)
|
||||||
|
})
|
||||||
|
.next();
|
||||||
let callee_ty = autoderef.unambiguous_final_ty();
|
let callee_ty = autoderef.unambiguous_final_ty();
|
||||||
autoderef.finalize(LvaluePreference::NoPreference, Some(callee_expr));
|
autoderef.finalize(LvaluePreference::NoPreference, Some(callee_expr));
|
||||||
|
|
||||||
|
@ -71,8 +75,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(CallStep::Overloaded(method_callee)) => {
|
Some(CallStep::Overloaded(method_callee)) => {
|
||||||
self.confirm_overloaded_call(call_expr, callee_expr,
|
self.confirm_overloaded_call(call_expr,
|
||||||
arg_exprs, expected, method_callee)
|
callee_expr,
|
||||||
|
arg_exprs,
|
||||||
|
expected,
|
||||||
|
method_callee)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -87,8 +94,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
callee_expr: &'gcx hir::Expr,
|
callee_expr: &'gcx hir::Expr,
|
||||||
adjusted_ty: Ty<'tcx>,
|
adjusted_ty: Ty<'tcx>,
|
||||||
autoderefs: usize)
|
autoderefs: usize)
|
||||||
-> Option<CallStep<'tcx>>
|
-> Option<CallStep<'tcx>> {
|
||||||
{
|
|
||||||
debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})",
|
debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})",
|
||||||
call_expr,
|
call_expr,
|
||||||
adjusted_ty,
|
adjusted_ty,
|
||||||
|
@ -108,20 +114,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// haven't yet decided on whether the closure is fn vs
|
// haven't yet decided on whether the closure is fn vs
|
||||||
// fnmut vs fnonce. If so, we have to defer further processing.
|
// fnmut vs fnonce. If so, we have to defer further processing.
|
||||||
if self.closure_kind(def_id).is_none() {
|
if self.closure_kind(def_id).is_none() {
|
||||||
let closure_ty =
|
let closure_ty = self.closure_type(def_id, substs);
|
||||||
self.closure_type(def_id, substs);
|
let fn_sig = self.replace_late_bound_regions_with_fresh_var(call_expr.span,
|
||||||
let fn_sig =
|
infer::FnCall,
|
||||||
self.replace_late_bound_regions_with_fresh_var(call_expr.span,
|
&closure_ty.sig)
|
||||||
infer::FnCall,
|
.0;
|
||||||
&closure_ty.sig).0;
|
self.record_deferred_call_resolution(def_id,
|
||||||
self.record_deferred_call_resolution(def_id, Box::new(CallResolution {
|
Box::new(CallResolution {
|
||||||
call_expr: call_expr,
|
call_expr: call_expr,
|
||||||
callee_expr: callee_expr,
|
callee_expr: callee_expr,
|
||||||
adjusted_ty: adjusted_ty,
|
adjusted_ty: adjusted_ty,
|
||||||
autoderefs: autoderefs,
|
autoderefs: autoderefs,
|
||||||
fn_sig: fn_sig.clone(),
|
fn_sig: fn_sig.clone(),
|
||||||
closure_def_id: def_id
|
closure_def_id: def_id,
|
||||||
}));
|
}));
|
||||||
return Some(CallStep::DeferredClosure(fn_sig));
|
return Some(CallStep::DeferredClosure(fn_sig));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,14 +156,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
callee_expr: &hir::Expr,
|
callee_expr: &hir::Expr,
|
||||||
adjusted_ty: Ty<'tcx>,
|
adjusted_ty: Ty<'tcx>,
|
||||||
autoderefs: usize)
|
autoderefs: usize)
|
||||||
-> Option<ty::MethodCallee<'tcx>>
|
-> Option<ty::MethodCallee<'tcx>> {
|
||||||
{
|
|
||||||
// Try the options that are least restrictive on the caller first.
|
// Try the options that are least restrictive on the caller first.
|
||||||
for &(opt_trait_def_id, method_name) in &[
|
for &(opt_trait_def_id, method_name) in
|
||||||
(self.tcx.lang_items.fn_trait(), token::intern("call")),
|
&[(self.tcx.lang_items.fn_trait(), token::intern("call")),
|
||||||
(self.tcx.lang_items.fn_mut_trait(), token::intern("call_mut")),
|
(self.tcx.lang_items.fn_mut_trait(), token::intern("call_mut")),
|
||||||
(self.tcx.lang_items.fn_once_trait(), token::intern("call_once")),
|
(self.tcx.lang_items.fn_once_trait(), token::intern("call_once"))] {
|
||||||
] {
|
|
||||||
let trait_def_id = match opt_trait_def_id {
|
let trait_def_id = match opt_trait_def_id {
|
||||||
Some(def_id) => def_id,
|
Some(def_id) => def_id,
|
||||||
None => continue,
|
None => continue,
|
||||||
|
@ -185,19 +189,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
call_expr: &hir::Expr,
|
call_expr: &hir::Expr,
|
||||||
callee_ty: Ty<'tcx>,
|
callee_ty: Ty<'tcx>,
|
||||||
arg_exprs: &'gcx [P<hir::Expr>],
|
arg_exprs: &'gcx [P<hir::Expr>],
|
||||||
expected: Expectation<'tcx>) -> Ty<'tcx>
|
expected: Expectation<'tcx>)
|
||||||
{
|
-> Ty<'tcx> {
|
||||||
let error_fn_sig;
|
let error_fn_sig;
|
||||||
|
|
||||||
let fn_sig = match callee_ty.sty {
|
let fn_sig = match callee_ty.sty {
|
||||||
ty::TyFnDef(.., &ty::BareFnTy {ref sig, ..}) |
|
ty::TyFnDef(.., &ty::BareFnTy { ref sig, .. }) |
|
||||||
ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => {
|
ty::TyFnPtr(&ty::BareFnTy { ref sig, .. }) => sig,
|
||||||
sig
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
let mut err = self.type_error_struct(call_expr.span, |actual| {
|
let mut err = self.type_error_struct(call_expr.span,
|
||||||
format!("expected function, found `{}`", actual)
|
|actual| {
|
||||||
}, callee_ty);
|
format!("expected function, found `{}`",
|
||||||
|
actual)
|
||||||
|
},
|
||||||
|
callee_ty);
|
||||||
|
|
||||||
if let hir::ExprCall(ref expr, _) = call_expr.node {
|
if let hir::ExprCall(ref expr, _) = call_expr.node {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
@ -218,7 +223,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
error_fn_sig = ty::Binder(ty::FnSig {
|
error_fn_sig = ty::Binder(ty::FnSig {
|
||||||
inputs: self.err_args(arg_exprs.len()),
|
inputs: self.err_args(arg_exprs.len()),
|
||||||
output: self.tcx.types.err,
|
output: self.tcx.types.err,
|
||||||
variadic: false
|
variadic: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
&error_fn_sig
|
&error_fn_sig
|
||||||
|
@ -231,17 +236,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// previously appeared within a `Binder<>` and hence would not
|
// previously appeared within a `Binder<>` and hence would not
|
||||||
// have been normalized before.
|
// have been normalized before.
|
||||||
let fn_sig =
|
let fn_sig =
|
||||||
self.replace_late_bound_regions_with_fresh_var(call_expr.span,
|
self.replace_late_bound_regions_with_fresh_var(call_expr.span, infer::FnCall, fn_sig)
|
||||||
infer::FnCall,
|
.0;
|
||||||
fn_sig).0;
|
let fn_sig = self.normalize_associated_types_in(call_expr.span, &fn_sig);
|
||||||
let fn_sig =
|
|
||||||
self.normalize_associated_types_in(call_expr.span, &fn_sig);
|
|
||||||
|
|
||||||
// Call the generic checker.
|
// Call the generic checker.
|
||||||
let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span,
|
let expected_arg_tys =
|
||||||
expected,
|
self.expected_types_for_fn_args(call_expr.span,
|
||||||
fn_sig.output,
|
expected,
|
||||||
&fn_sig.inputs);
|
fn_sig.output,
|
||||||
|
&fn_sig.inputs);
|
||||||
self.check_argument_types(call_expr.span,
|
self.check_argument_types(call_expr.span,
|
||||||
&fn_sig.inputs,
|
&fn_sig.inputs,
|
||||||
&expected_arg_tys[..],
|
&expected_arg_tys[..],
|
||||||
|
@ -256,18 +260,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
call_expr: &hir::Expr,
|
call_expr: &hir::Expr,
|
||||||
arg_exprs: &'gcx [P<hir::Expr>],
|
arg_exprs: &'gcx [P<hir::Expr>],
|
||||||
expected: Expectation<'tcx>,
|
expected: Expectation<'tcx>,
|
||||||
fn_sig: ty::FnSig<'tcx>) -> Ty<'tcx>
|
fn_sig: ty::FnSig<'tcx>)
|
||||||
{
|
-> Ty<'tcx> {
|
||||||
// `fn_sig` is the *signature* of the cosure being called. We
|
// `fn_sig` is the *signature* of the cosure being called. We
|
||||||
// don't know the full details yet (`Fn` vs `FnMut` etc), but we
|
// don't know the full details yet (`Fn` vs `FnMut` etc), but we
|
||||||
// do know the types expected for each argument and the return
|
// do know the types expected for each argument and the return
|
||||||
// type.
|
// type.
|
||||||
|
|
||||||
let expected_arg_tys =
|
let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span,
|
||||||
self.expected_types_for_fn_args(call_expr.span,
|
expected,
|
||||||
expected,
|
fn_sig.output.clone(),
|
||||||
fn_sig.output.clone(),
|
&fn_sig.inputs);
|
||||||
&fn_sig.inputs);
|
|
||||||
|
|
||||||
self.check_argument_types(call_expr.span,
|
self.check_argument_types(call_expr.span,
|
||||||
&fn_sig.inputs,
|
&fn_sig.inputs,
|
||||||
|
@ -284,15 +287,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
callee_expr: &'gcx hir::Expr,
|
callee_expr: &'gcx hir::Expr,
|
||||||
arg_exprs: &'gcx [P<hir::Expr>],
|
arg_exprs: &'gcx [P<hir::Expr>],
|
||||||
expected: Expectation<'tcx>,
|
expected: Expectation<'tcx>,
|
||||||
method_callee: ty::MethodCallee<'tcx>) -> Ty<'tcx>
|
method_callee: ty::MethodCallee<'tcx>)
|
||||||
{
|
-> Ty<'tcx> {
|
||||||
let output_type =
|
let output_type = self.check_method_argument_types(call_expr.span,
|
||||||
self.check_method_argument_types(call_expr.span,
|
method_callee.ty,
|
||||||
method_callee.ty,
|
callee_expr,
|
||||||
callee_expr,
|
arg_exprs,
|
||||||
arg_exprs,
|
TupleArgumentsFlag::TupleArguments,
|
||||||
TupleArgumentsFlag::TupleArguments,
|
expected);
|
||||||
expected);
|
|
||||||
|
|
||||||
self.write_overloaded_call_method_map(call_expr, method_callee);
|
self.write_overloaded_call_method_map(call_expr, method_callee);
|
||||||
output_type
|
output_type
|
||||||
|
@ -318,16 +320,17 @@ struct CallResolution<'gcx: 'tcx, 'tcx> {
|
||||||
|
|
||||||
impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tcx> {
|
impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tcx> {
|
||||||
fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
|
fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
|
||||||
debug!("DeferredCallResolution::resolve() {:?}",
|
debug!("DeferredCallResolution::resolve() {:?}", self);
|
||||||
self);
|
|
||||||
|
|
||||||
// we should not be invoked until the closure kind has been
|
// we should not be invoked until the closure kind has been
|
||||||
// determined by upvar inference
|
// determined by upvar inference
|
||||||
assert!(fcx.closure_kind(self.closure_def_id).is_some());
|
assert!(fcx.closure_kind(self.closure_def_id).is_some());
|
||||||
|
|
||||||
// We may now know enough to figure out fn vs fnmut etc.
|
// We may now know enough to figure out fn vs fnmut etc.
|
||||||
match fcx.try_overloaded_call_traits(self.call_expr, self.callee_expr,
|
match fcx.try_overloaded_call_traits(self.call_expr,
|
||||||
self.adjusted_ty, self.autoderefs) {
|
self.callee_expr,
|
||||||
|
self.adjusted_ty,
|
||||||
|
self.autoderefs) {
|
||||||
Some(method_callee) => {
|
Some(method_callee) => {
|
||||||
// One problem is that when we get here, we are going
|
// One problem is that when we get here, we are going
|
||||||
// to have a newly instantiated function signature
|
// to have a newly instantiated function signature
|
||||||
|
@ -337,28 +340,24 @@ impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tc
|
||||||
// can't because of the annoying need for a TypeTrace.
|
// can't because of the annoying need for a TypeTrace.
|
||||||
// (This always bites me, should find a way to
|
// (This always bites me, should find a way to
|
||||||
// refactor it.)
|
// refactor it.)
|
||||||
let method_sig = fcx.tcx.no_late_bound_regions(method_callee.ty.fn_sig())
|
let method_sig = fcx.tcx
|
||||||
.unwrap();
|
.no_late_bound_regions(method_callee.ty.fn_sig())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
debug!("attempt_resolution: method_callee={:?}",
|
debug!("attempt_resolution: method_callee={:?}", method_callee);
|
||||||
method_callee);
|
|
||||||
|
|
||||||
for (&method_arg_ty, &self_arg_ty) in
|
for (&method_arg_ty, &self_arg_ty) in
|
||||||
method_sig.inputs[1..].iter().zip(&self.fn_sig.inputs)
|
method_sig.inputs[1..].iter().zip(&self.fn_sig.inputs) {
|
||||||
{
|
|
||||||
fcx.demand_eqtype(self.call_expr.span, self_arg_ty, method_arg_ty);
|
fcx.demand_eqtype(self.call_expr.span, self_arg_ty, method_arg_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
fcx.demand_eqtype(self.call_expr.span,
|
fcx.demand_eqtype(self.call_expr.span, method_sig.output, self.fn_sig.output);
|
||||||
method_sig.output,
|
|
||||||
self.fn_sig.output);
|
|
||||||
|
|
||||||
fcx.write_overloaded_call_method_map(self.call_expr, method_callee);
|
fcx.write_overloaded_call_method_map(self.call_expr, method_callee);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
span_bug!(
|
span_bug!(self.call_expr.span,
|
||||||
self.call_expr.span,
|
"failed to find an overloaded call trait for closure call");
|
||||||
"failed to find an overloaded call trait for closure call");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ enum UnsizeKind<'tcx> {
|
||||||
/// The unsize info of this projection
|
/// The unsize info of this projection
|
||||||
OfProjection(&'tcx ty::ProjectionTy<'tcx>),
|
OfProjection(&'tcx ty::ProjectionTy<'tcx>),
|
||||||
/// The unsize info of this parameter
|
/// The unsize info of this parameter
|
||||||
OfParam(&'tcx ty::ParamTy)
|
OfParam(&'tcx ty::ParamTy),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
@ -83,13 +83,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// FIXME(arielb1): do some kind of normalization
|
// FIXME(arielb1): do some kind of normalization
|
||||||
match def.struct_variant().fields.last() {
|
match def.struct_variant().fields.last() {
|
||||||
None => None,
|
None => None,
|
||||||
Some(f) => self.unsize_kind(f.ty(self.tcx, substs))
|
Some(f) => self.unsize_kind(f.ty(self.tcx, substs)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We should really try to normalize here.
|
// We should really try to normalize here.
|
||||||
ty::TyProjection(ref pi) => Some(UnsizeKind::OfProjection(pi)),
|
ty::TyProjection(ref pi) => Some(UnsizeKind::OfProjection(pi)),
|
||||||
ty::TyParam(ref p) => Some(UnsizeKind::OfParam(p)),
|
ty::TyParam(ref p) => Some(UnsizeKind::OfParam(p)),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,9 +133,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||||
check.report_cast_to_unsized_type(fcx);
|
check.report_cast_to_unsized_type(fcx);
|
||||||
Err(ErrorReported)
|
Err(ErrorReported)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => Ok(check),
|
||||||
Ok(check)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,18 +143,21 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||||
CastError::NeedViaThinPtr |
|
CastError::NeedViaThinPtr |
|
||||||
CastError::NeedViaInt |
|
CastError::NeedViaInt |
|
||||||
CastError::NeedViaUsize => {
|
CastError::NeedViaUsize => {
|
||||||
fcx.type_error_struct(self.span, |actual| {
|
fcx.type_error_struct(self.span,
|
||||||
format!("casting `{}` as `{}` is invalid",
|
|actual| {
|
||||||
actual,
|
format!("casting `{}` as `{}` is invalid",
|
||||||
fcx.ty_to_string(self.cast_ty))
|
actual,
|
||||||
}, self.expr_ty)
|
fcx.ty_to_string(self.cast_ty))
|
||||||
.help(&format!("cast through {} first", match e {
|
},
|
||||||
CastError::NeedViaPtr => "a raw pointer",
|
self.expr_ty)
|
||||||
CastError::NeedViaThinPtr => "a thin pointer",
|
.help(&format!("cast through {} first",
|
||||||
CastError::NeedViaInt => "an integer",
|
match e {
|
||||||
CastError::NeedViaUsize => "a usize",
|
CastError::NeedViaPtr => "a raw pointer",
|
||||||
_ => bug!()
|
CastError::NeedViaThinPtr => "a thin pointer",
|
||||||
}))
|
CastError::NeedViaInt => "an integer",
|
||||||
|
CastError::NeedViaUsize => "a usize",
|
||||||
|
_ => bug!(),
|
||||||
|
}))
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
CastError::CastToBool => {
|
CastError::CastToBool => {
|
||||||
|
@ -166,37 +167,49 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
CastError::CastToChar => {
|
CastError::CastToChar => {
|
||||||
fcx.type_error_message(self.span, |actual| {
|
fcx.type_error_message(self.span,
|
||||||
format!("only `u8` can be cast as `char`, not `{}`", actual)
|
|actual| {
|
||||||
}, self.expr_ty);
|
format!("only `u8` can be cast as `char`, not `{}`",
|
||||||
|
actual)
|
||||||
|
},
|
||||||
|
self.expr_ty);
|
||||||
}
|
}
|
||||||
CastError::NonScalar => {
|
CastError::NonScalar => {
|
||||||
fcx.type_error_message(self.span, |actual| {
|
fcx.type_error_message(self.span,
|
||||||
format!("non-scalar cast: `{}` as `{}`",
|
|actual| {
|
||||||
actual,
|
format!("non-scalar cast: `{}` as `{}`",
|
||||||
fcx.ty_to_string(self.cast_ty))
|
actual,
|
||||||
}, self.expr_ty);
|
fcx.ty_to_string(self.cast_ty))
|
||||||
|
},
|
||||||
|
self.expr_ty);
|
||||||
}
|
}
|
||||||
CastError::IllegalCast => {
|
CastError::IllegalCast => {
|
||||||
fcx.type_error_message(self.span, |actual| {
|
fcx.type_error_message(self.span,
|
||||||
format!("casting `{}` as `{}` is invalid",
|
|actual| {
|
||||||
actual,
|
format!("casting `{}` as `{}` is invalid",
|
||||||
fcx.ty_to_string(self.cast_ty))
|
actual,
|
||||||
}, self.expr_ty);
|
fcx.ty_to_string(self.cast_ty))
|
||||||
|
},
|
||||||
|
self.expr_ty);
|
||||||
}
|
}
|
||||||
CastError::SizedUnsizedCast => {
|
CastError::SizedUnsizedCast => {
|
||||||
fcx.type_error_message(self.span, |actual| {
|
fcx.type_error_message(self.span,
|
||||||
format!("cannot cast thin pointer `{}` to fat pointer `{}`",
|
|actual| {
|
||||||
actual,
|
format!("cannot cast thin pointer `{}` to fat pointer \
|
||||||
fcx.ty_to_string(self.cast_ty))
|
`{}`",
|
||||||
}, self.expr_ty)
|
actual,
|
||||||
|
fcx.ty_to_string(self.cast_ty))
|
||||||
|
},
|
||||||
|
self.expr_ty)
|
||||||
}
|
}
|
||||||
CastError::DifferingKinds => {
|
CastError::DifferingKinds => {
|
||||||
fcx.type_error_struct(self.span, |actual| {
|
fcx.type_error_struct(self.span,
|
||||||
format!("casting `{}` as `{}` is invalid",
|
|actual| {
|
||||||
actual,
|
format!("casting `{}` as `{}` is invalid",
|
||||||
fcx.ty_to_string(self.cast_ty))
|
actual,
|
||||||
}, self.expr_ty)
|
fcx.ty_to_string(self.cast_ty))
|
||||||
|
},
|
||||||
|
self.expr_ty)
|
||||||
.note("vtable kinds may not match")
|
.note("vtable kinds may not match")
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
@ -204,22 +217,22 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
|
fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
|
||||||
if
|
if self.cast_ty.references_error() || self.expr_ty.references_error() {
|
||||||
self.cast_ty.references_error() ||
|
|
||||||
self.expr_ty.references_error()
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let tstr = fcx.ty_to_string(self.cast_ty);
|
let tstr = fcx.ty_to_string(self.cast_ty);
|
||||||
let mut err = fcx.type_error_struct(self.span, |actual| {
|
let mut err =
|
||||||
format!("cast to unsized type: `{}` as `{}`", actual, tstr)
|
fcx.type_error_struct(self.span,
|
||||||
}, self.expr_ty);
|
|actual| {
|
||||||
|
format!("cast to unsized type: `{}` as `{}`", actual, tstr)
|
||||||
|
},
|
||||||
|
self.expr_ty);
|
||||||
match self.expr_ty.sty {
|
match self.expr_ty.sty {
|
||||||
ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => {
|
ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => {
|
||||||
let mtstr = match mt {
|
let mtstr = match mt {
|
||||||
hir::MutMutable => "mut ",
|
hir::MutMutable => "mut ",
|
||||||
hir::MutImmutable => ""
|
hir::MutImmutable => "",
|
||||||
};
|
};
|
||||||
if self.cast_ty.is_trait() {
|
if self.cast_ty.is_trait() {
|
||||||
match fcx.tcx.sess.codemap().span_to_snippet(self.cast_span) {
|
match fcx.tcx.sess.codemap().span_to_snippet(self.cast_span) {
|
||||||
|
@ -227,15 +240,17 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||||
err.span_suggestion(self.cast_span,
|
err.span_suggestion(self.cast_span,
|
||||||
"try casting to a reference instead:",
|
"try casting to a reference instead:",
|
||||||
format!("&{}{}", mtstr, s));
|
format!("&{}{}", mtstr, s));
|
||||||
},
|
}
|
||||||
Err(_) =>
|
Err(_) => {
|
||||||
span_help!(err, self.cast_span,
|
span_help!(err, self.cast_span, "did you mean `&{}{}`?", mtstr, tstr)
|
||||||
"did you mean `&{}{}`?", mtstr, tstr),
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
span_help!(err, self.span,
|
span_help!(err,
|
||||||
|
self.span,
|
||||||
"consider using an implicit coercion to `&{}{}` instead",
|
"consider using an implicit coercion to `&{}{}` instead",
|
||||||
mtstr, tstr);
|
mtstr,
|
||||||
|
tstr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::TyBox(..) => {
|
ty::TyBox(..) => {
|
||||||
|
@ -244,13 +259,13 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||||
err.span_suggestion(self.cast_span,
|
err.span_suggestion(self.cast_span,
|
||||||
"try casting to a `Box` instead:",
|
"try casting to a `Box` instead:",
|
||||||
format!("Box<{}>", s));
|
format!("Box<{}>", s));
|
||||||
},
|
}
|
||||||
Err(_) =>
|
Err(_) => span_help!(err, self.cast_span, "did you mean `Box<{}>`?", tstr),
|
||||||
span_help!(err, self.cast_span, "did you mean `Box<{}>`?", tstr),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
span_help!(err, self.expr.span,
|
span_help!(err,
|
||||||
|
self.expr.span,
|
||||||
"consider using a box or reference as appropriate");
|
"consider using a box or reference as appropriate");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,7 +301,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||||
self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty);
|
self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty);
|
||||||
self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty);
|
self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty);
|
||||||
|
|
||||||
debug!("check_cast({}, {:?} as {:?})", self.expr.id, self.expr_ty,
|
debug!("check_cast({}, {:?} as {:?})",
|
||||||
|
self.expr.id,
|
||||||
|
self.expr_ty,
|
||||||
self.cast_ty);
|
self.cast_ty);
|
||||||
|
|
||||||
if !fcx.type_is_known_to_be_sized(self.cast_ty, self.span) {
|
if !fcx.type_is_known_to_be_sized(self.cast_ty, self.span) {
|
||||||
|
@ -296,15 +313,16 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||||
} else if self.try_coercion_cast(fcx) {
|
} else if self.try_coercion_cast(fcx) {
|
||||||
self.trivial_cast_lint(fcx);
|
self.trivial_cast_lint(fcx);
|
||||||
debug!(" -> CoercionCast");
|
debug!(" -> CoercionCast");
|
||||||
fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id,
|
fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id, CastKind::CoercionCast);
|
||||||
CastKind::CoercionCast);
|
} else {
|
||||||
} else { match self.do_check(fcx) {
|
match self.do_check(fcx) {
|
||||||
Ok(k) => {
|
Ok(k) => {
|
||||||
debug!(" -> {:?}", k);
|
debug!(" -> {:?}", k);
|
||||||
fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id, k);
|
fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id, k);
|
||||||
}
|
}
|
||||||
Err(e) => self.report_cast_error(fcx, e)
|
Err(e) => self.report_cast_error(fcx, e),
|
||||||
};}
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check a cast, and report an error if one exists. In some cases, this
|
/// Check a cast, and report an error if one exists. In some cases, this
|
||||||
|
@ -330,9 +348,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||||
return Err(CastError::NonScalar);
|
return Err(CastError::NonScalar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => return Err(CastError::NonScalar),
|
||||||
return Err(CastError::NonScalar)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match (t_from, t_cast) {
|
match (t_from, t_cast) {
|
||||||
|
@ -347,17 +363,20 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||||
(_, Int(Char)) => Err(CastError::CastToChar),
|
(_, Int(Char)) => Err(CastError::CastToChar),
|
||||||
|
|
||||||
// prim -> float,ptr
|
// prim -> float,ptr
|
||||||
(Int(Bool), Float) | (Int(CEnum), Float) | (Int(Char), Float)
|
(Int(Bool), Float) |
|
||||||
=> Err(CastError::NeedViaInt),
|
(Int(CEnum), Float) |
|
||||||
(Int(Bool), Ptr(_)) | (Int(CEnum), Ptr(_)) | (Int(Char), Ptr(_))
|
(Int(Char), Float) => Err(CastError::NeedViaInt),
|
||||||
=> Err(CastError::NeedViaUsize),
|
(Int(Bool), Ptr(_)) |
|
||||||
|
(Int(CEnum), Ptr(_)) |
|
||||||
|
(Int(Char), Ptr(_)) => Err(CastError::NeedViaUsize),
|
||||||
|
|
||||||
// ptr -> *
|
// ptr -> *
|
||||||
(Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
|
(Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
|
||||||
(Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
|
(Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
|
||||||
(Ptr(_), Float) | (FnPtr, Float) => Err(CastError::NeedViaUsize),
|
(Ptr(_), Float) | (FnPtr, Float) => Err(CastError::NeedViaUsize),
|
||||||
(FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
|
(FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
|
||||||
(RPtr(_), Int(_)) | (RPtr(_), Float) => Err(CastError::NeedViaPtr),
|
(RPtr(_), Int(_)) |
|
||||||
|
(RPtr(_), Float) => Err(CastError::NeedViaPtr),
|
||||||
// * -> ptr
|
// * -> ptr
|
||||||
(Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
|
(Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
|
||||||
(FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
|
(FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
|
||||||
|
@ -366,12 +385,12 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||||
|
|
||||||
// prim -> prim
|
// prim -> prim
|
||||||
(Int(CEnum), Int(_)) => Ok(CastKind::EnumCast),
|
(Int(CEnum), Int(_)) => Ok(CastKind::EnumCast),
|
||||||
(Int(Char), Int(_)) | (Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
|
(Int(Char), Int(_)) |
|
||||||
|
(Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
|
||||||
|
|
||||||
(Int(_), Int(_)) |
|
(Int(_), Int(_)) | (Int(_), Float) | (Float, Int(_)) | (Float, Float) => {
|
||||||
(Int(_), Float) |
|
Ok(CastKind::NumericCast)
|
||||||
(Float, Int(_)) |
|
}
|
||||||
(Float, Float) => Ok(CastKind::NumericCast),
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,10 +399,8 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||||
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
|
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
|
||||||
m_expr: &'tcx ty::TypeAndMut<'tcx>,
|
m_expr: &'tcx ty::TypeAndMut<'tcx>,
|
||||||
m_cast: &'tcx ty::TypeAndMut<'tcx>)
|
m_cast: &'tcx ty::TypeAndMut<'tcx>)
|
||||||
-> Result<CastKind, CastError>
|
-> Result<CastKind, CastError> {
|
||||||
{
|
debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast);
|
||||||
debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}",
|
|
||||||
m_expr, m_cast);
|
|
||||||
// ptr-ptr cast. vtables must match.
|
// ptr-ptr cast. vtables must match.
|
||||||
|
|
||||||
// Cast to sized is OK
|
// Cast to sized is OK
|
||||||
|
@ -399,15 +416,14 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||||
// vtable kinds must match
|
// vtable kinds must match
|
||||||
match (fcx.unsize_kind(m_cast.ty), fcx.unsize_kind(m_expr.ty)) {
|
match (fcx.unsize_kind(m_cast.ty), fcx.unsize_kind(m_expr.ty)) {
|
||||||
(Some(a), Some(b)) if a == b => Ok(CastKind::PtrPtrCast),
|
(Some(a), Some(b)) if a == b => Ok(CastKind::PtrPtrCast),
|
||||||
_ => Err(CastError::DifferingKinds)
|
_ => Err(CastError::DifferingKinds),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_fptr_ptr_cast(&self,
|
fn check_fptr_ptr_cast(&self,
|
||||||
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
|
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
|
||||||
m_cast: &'tcx ty::TypeAndMut<'tcx>)
|
m_cast: &'tcx ty::TypeAndMut<'tcx>)
|
||||||
-> Result<CastKind, CastError>
|
-> Result<CastKind, CastError> {
|
||||||
{
|
|
||||||
// fptr-ptr cast. must be to sized ptr
|
// fptr-ptr cast. must be to sized ptr
|
||||||
|
|
||||||
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
|
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
|
||||||
|
@ -420,8 +436,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||||
fn check_ptr_addr_cast(&self,
|
fn check_ptr_addr_cast(&self,
|
||||||
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
|
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
|
||||||
m_expr: &'tcx ty::TypeAndMut<'tcx>)
|
m_expr: &'tcx ty::TypeAndMut<'tcx>)
|
||||||
-> Result<CastKind, CastError>
|
-> Result<CastKind, CastError> {
|
||||||
{
|
|
||||||
// ptr-addr cast. must be from sized ptr
|
// ptr-addr cast. must be from sized ptr
|
||||||
|
|
||||||
if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
|
if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
|
||||||
|
@ -435,8 +450,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||||
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
|
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
|
||||||
m_expr: &'tcx ty::TypeAndMut<'tcx>,
|
m_expr: &'tcx ty::TypeAndMut<'tcx>,
|
||||||
m_cast: &'tcx ty::TypeAndMut<'tcx>)
|
m_cast: &'tcx ty::TypeAndMut<'tcx>)
|
||||||
-> Result<CastKind, CastError>
|
-> Result<CastKind, CastError> {
|
||||||
{
|
|
||||||
// array-ptr-cast.
|
// array-ptr-cast.
|
||||||
|
|
||||||
if m_expr.mutbl == hir::MutImmutable && m_cast.mutbl == hir::MutImmutable {
|
if m_expr.mutbl == hir::MutImmutable && m_cast.mutbl == hir::MutImmutable {
|
||||||
|
@ -460,28 +474,22 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||||
fn check_addr_ptr_cast(&self,
|
fn check_addr_ptr_cast(&self,
|
||||||
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
|
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
|
||||||
m_cast: &'tcx ty::TypeAndMut<'tcx>)
|
m_cast: &'tcx ty::TypeAndMut<'tcx>)
|
||||||
-> Result<CastKind, CastError>
|
-> Result<CastKind, CastError> {
|
||||||
{
|
|
||||||
// ptr-addr cast. pointer must be thin.
|
// ptr-addr cast. pointer must be thin.
|
||||||
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
|
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
|
||||||
Ok(CastKind::AddrPtrCast)
|
Ok(CastKind::AddrPtrCast)
|
||||||
} else {
|
} else {
|
||||||
Err(CastError::IllegalCast)
|
Err(CastError::IllegalCast)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool {
|
fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool {
|
||||||
fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty).is_ok()
|
fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
fn type_is_known_to_be_sized(&self,
|
fn type_is_known_to_be_sized(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||||
ty: Ty<'tcx>,
|
|
||||||
span: Span)
|
|
||||||
-> bool
|
|
||||||
{
|
|
||||||
traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span)
|
traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
_capture: hir::CaptureClause,
|
_capture: hir::CaptureClause,
|
||||||
decl: &'gcx hir::FnDecl,
|
decl: &'gcx hir::FnDecl,
|
||||||
body: &'gcx hir::Block,
|
body: &'gcx hir::Block,
|
||||||
expected: Expectation<'tcx>) -> Ty<'tcx> {
|
expected: Expectation<'tcx>)
|
||||||
|
-> Ty<'tcx> {
|
||||||
debug!("check_expr_closure(expr={:?},expected={:?})",
|
debug!("check_expr_closure(expr={:?},expected={:?})",
|
||||||
expr,
|
expr,
|
||||||
expected);
|
expected);
|
||||||
|
@ -32,9 +33,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// It's always helpful for inference if we know the kind of
|
// It's always helpful for inference if we know the kind of
|
||||||
// closure sooner rather than later, so first examine the expected
|
// closure sooner rather than later, so first examine the expected
|
||||||
// type, and see if can glean a closure kind from there.
|
// type, and see if can glean a closure kind from there.
|
||||||
let (expected_sig,expected_kind) = match expected.to_option(self) {
|
let (expected_sig, expected_kind) = match expected.to_option(self) {
|
||||||
Some(ty) => self.deduce_expectations_from_expected_type(ty),
|
Some(ty) => self.deduce_expectations_from_expected_type(ty),
|
||||||
None => (None, None)
|
None => (None, None),
|
||||||
};
|
};
|
||||||
self.check_closure(expr, expected_kind, decl, body, expected_sig)
|
self.check_closure(expr, expected_kind, decl, body, expected_sig)
|
||||||
}
|
}
|
||||||
|
@ -44,7 +45,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
opt_kind: Option<ty::ClosureKind>,
|
opt_kind: Option<ty::ClosureKind>,
|
||||||
decl: &'gcx hir::FnDecl,
|
decl: &'gcx hir::FnDecl,
|
||||||
body: &'gcx hir::Block,
|
body: &'gcx hir::Block,
|
||||||
expected_sig: Option<ty::FnSig<'tcx>>) -> Ty<'tcx> {
|
expected_sig: Option<ty::FnSig<'tcx>>)
|
||||||
|
-> Ty<'tcx> {
|
||||||
let expr_def_id = self.tcx.map.local_def_id(expr.id);
|
let expr_def_id = self.tcx.map.local_def_id(expr.id);
|
||||||
|
|
||||||
debug!("check_closure opt_kind={:?} expected_sig={:?}",
|
debug!("check_closure opt_kind={:?} expected_sig={:?}",
|
||||||
|
@ -64,18 +66,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
let upvar_tys = self.next_ty_vars(num_upvars);
|
let upvar_tys = self.next_ty_vars(num_upvars);
|
||||||
|
|
||||||
debug!("check_closure: expr.id={:?} upvar_tys={:?}",
|
debug!("check_closure: expr.id={:?} upvar_tys={:?}",
|
||||||
expr.id, upvar_tys);
|
expr.id,
|
||||||
|
upvar_tys);
|
||||||
|
|
||||||
let closure_type = self.tcx.mk_closure(expr_def_id,
|
let closure_type = self.tcx.mk_closure(expr_def_id,
|
||||||
self.parameter_environment.free_substs,
|
self.parameter_environment.free_substs,
|
||||||
upvar_tys);
|
upvar_tys);
|
||||||
|
|
||||||
let fn_sig = self.tcx.liberate_late_bound_regions(
|
let fn_sig = self.tcx
|
||||||
self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig);
|
.liberate_late_bound_regions(self.tcx.region_maps.call_site_extent(expr.id, body.id),
|
||||||
let fn_sig =
|
&fn_ty.sig);
|
||||||
(**self).normalize_associated_types_in(body.span, body.id, &fn_sig);
|
let fn_sig = (**self).normalize_associated_types_in(body.span, body.id, &fn_sig);
|
||||||
|
|
||||||
check_fn(self, hir::Unsafety::Normal, expr.id, &fn_sig, decl, expr.id, &body);
|
check_fn(self,
|
||||||
|
hir::Unsafety::Normal,
|
||||||
|
expr.id,
|
||||||
|
&fn_sig,
|
||||||
|
decl,
|
||||||
|
expr.id,
|
||||||
|
&body);
|
||||||
|
|
||||||
// Tuple up the arguments and insert the resulting function type into
|
// Tuple up the arguments and insert the resulting function type into
|
||||||
// the `closures` table.
|
// the `closures` table.
|
||||||
|
@ -88,46 +97,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
self.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty);
|
self.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty);
|
||||||
match opt_kind {
|
match opt_kind {
|
||||||
Some(kind) => { self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); }
|
Some(kind) => {
|
||||||
None => { }
|
self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind);
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
closure_type
|
closure_type
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>)
|
fn deduce_expectations_from_expected_type
|
||||||
-> (Option<ty::FnSig<'tcx>>,Option<ty::ClosureKind>)
|
(&self,
|
||||||
{
|
expected_ty: Ty<'tcx>)
|
||||||
|
-> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||||
debug!("deduce_expectations_from_expected_type(expected_ty={:?})",
|
debug!("deduce_expectations_from_expected_type(expected_ty={:?})",
|
||||||
expected_ty);
|
expected_ty);
|
||||||
|
|
||||||
match expected_ty.sty {
|
match expected_ty.sty {
|
||||||
ty::TyTrait(ref object_type) => {
|
ty::TyTrait(ref object_type) => {
|
||||||
let sig = object_type.projection_bounds.iter().filter_map(|pb| {
|
let sig = object_type.projection_bounds
|
||||||
let pb = pb.with_self_ty(self.tcx, self.tcx.types.err);
|
.iter()
|
||||||
self.deduce_sig_from_projection(&pb)
|
.filter_map(|pb| {
|
||||||
}).next();
|
let pb = pb.with_self_ty(self.tcx, self.tcx.types.err);
|
||||||
|
self.deduce_sig_from_projection(&pb)
|
||||||
|
})
|
||||||
|
.next();
|
||||||
let kind = self.tcx.lang_items.fn_trait_kind(object_type.principal.def_id());
|
let kind = self.tcx.lang_items.fn_trait_kind(object_type.principal.def_id());
|
||||||
(sig, kind)
|
(sig, kind)
|
||||||
}
|
}
|
||||||
ty::TyInfer(ty::TyVar(vid)) => {
|
ty::TyInfer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
|
||||||
self.deduce_expectations_from_obligations(vid)
|
_ => (None, None),
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
(None, None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deduce_expectations_from_obligations(&self, expected_vid: ty::TyVid)
|
fn deduce_expectations_from_obligations
|
||||||
-> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>)
|
(&self,
|
||||||
{
|
expected_vid: ty::TyVid)
|
||||||
|
-> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||||
let fulfillment_cx = self.fulfillment_cx.borrow();
|
let fulfillment_cx = self.fulfillment_cx.borrow();
|
||||||
// Here `expected_ty` is known to be a type inference variable.
|
// Here `expected_ty` is known to be a type inference variable.
|
||||||
|
|
||||||
let expected_sig =
|
let expected_sig = fulfillment_cx.pending_obligations()
|
||||||
fulfillment_cx
|
|
||||||
.pending_obligations()
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|obligation| &obligation.obligation)
|
.map(|obligation| &obligation.obligation)
|
||||||
.filter_map(|obligation| {
|
.filter_map(|obligation| {
|
||||||
|
@ -142,9 +152,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
self.self_type_matches_expected_vid(trait_ref, expected_vid)
|
self.self_type_matches_expected_vid(trait_ref, expected_vid)
|
||||||
.and_then(|_| self.deduce_sig_from_projection(proj_predicate))
|
.and_then(|_| self.deduce_sig_from_projection(proj_predicate))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => None,
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.next();
|
.next();
|
||||||
|
@ -153,9 +161,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// infer the kind. This can occur if there is a trait-reference
|
// infer the kind. This can occur if there is a trait-reference
|
||||||
// like `F : Fn<A>`. Note that due to subtyping we could encounter
|
// like `F : Fn<A>`. Note that due to subtyping we could encounter
|
||||||
// many viable options, so pick the most restrictive.
|
// many viable options, so pick the most restrictive.
|
||||||
let expected_kind =
|
let expected_kind = fulfillment_cx.pending_obligations()
|
||||||
fulfillment_cx
|
|
||||||
.pending_obligations()
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|obligation| &obligation.obligation)
|
.map(|obligation| &obligation.obligation)
|
||||||
.filter_map(|obligation| {
|
.filter_map(|obligation| {
|
||||||
|
@ -178,11 +184,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// inference variable.
|
// inference variable.
|
||||||
ty::Predicate::ClosureKind(..) => None,
|
ty::Predicate::ClosureKind(..) => None,
|
||||||
};
|
};
|
||||||
opt_trait_ref
|
opt_trait_ref.and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid))
|
||||||
.and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid))
|
|
||||||
.and_then(|tr| self.tcx.lang_items.fn_trait_kind(tr.def_id()))
|
.and_then(|tr| self.tcx.lang_items.fn_trait_kind(tr.def_id()))
|
||||||
})
|
})
|
||||||
.fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
|
.fold(None,
|
||||||
|
|best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
|
||||||
|
|
||||||
(expected_sig, expected_kind)
|
(expected_sig, expected_kind)
|
||||||
}
|
}
|
||||||
|
@ -190,13 +196,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
/// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
|
/// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
|
||||||
/// everything we need to know about a closure.
|
/// everything we need to know about a closure.
|
||||||
fn deduce_sig_from_projection(&self,
|
fn deduce_sig_from_projection(&self,
|
||||||
projection: &ty::PolyProjectionPredicate<'tcx>)
|
projection: &ty::PolyProjectionPredicate<'tcx>)
|
||||||
-> Option<ty::FnSig<'tcx>>
|
-> Option<ty::FnSig<'tcx>> {
|
||||||
{
|
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
||||||
debug!("deduce_sig_from_projection({:?})",
|
debug!("deduce_sig_from_projection({:?})", projection);
|
||||||
projection);
|
|
||||||
|
|
||||||
let trait_ref = projection.to_poly_trait_ref();
|
let trait_ref = projection.to_poly_trait_ref();
|
||||||
|
|
||||||
|
@ -206,22 +210,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
let arg_param_ty = trait_ref.substs().type_at(1);
|
let arg_param_ty = trait_ref.substs().type_at(1);
|
||||||
let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
|
let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
|
||||||
debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty);
|
debug!("deduce_sig_from_projection: arg_param_ty {:?}",
|
||||||
|
arg_param_ty);
|
||||||
|
|
||||||
let input_tys = match arg_param_ty.sty {
|
let input_tys = match arg_param_ty.sty {
|
||||||
ty::TyTuple(tys) => tys.to_vec(),
|
ty::TyTuple(tys) => tys.to_vec(),
|
||||||
_ => { return None; }
|
_ => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
debug!("deduce_sig_from_projection: input_tys {:?}", input_tys);
|
debug!("deduce_sig_from_projection: input_tys {:?}", input_tys);
|
||||||
|
|
||||||
let ret_param_ty = projection.0.ty;
|
let ret_param_ty = projection.0.ty;
|
||||||
let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
|
let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
|
||||||
debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);
|
debug!("deduce_sig_from_projection: ret_param_ty {:?}",
|
||||||
|
ret_param_ty);
|
||||||
|
|
||||||
let fn_sig = ty::FnSig {
|
let fn_sig = ty::FnSig {
|
||||||
inputs: input_tys,
|
inputs: input_tys,
|
||||||
output: ret_param_ty,
|
output: ret_param_ty,
|
||||||
variadic: false
|
variadic: false,
|
||||||
};
|
};
|
||||||
debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
|
debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
|
||||||
|
|
||||||
|
@ -229,10 +237,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn self_type_matches_expected_vid(&self,
|
fn self_type_matches_expected_vid(&self,
|
||||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||||
expected_vid: ty::TyVid)
|
expected_vid: ty::TyVid)
|
||||||
-> Option<ty::PolyTraitRef<'tcx>>
|
-> Option<ty::PolyTraitRef<'tcx>> {
|
||||||
{
|
|
||||||
let self_ty = self.shallow_resolve(trait_ref.self_ty());
|
let self_ty = self.shallow_resolve(trait_ref.self_ty());
|
||||||
debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
|
debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
|
||||||
trait_ref,
|
trait_ref,
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
//! sort of a minor point so I've opted to leave it for later---after all
|
//! sort of a minor point so I've opted to leave it for later---after all
|
||||||
//! we may want to adjust precisely when coercions occur.
|
//! we may want to adjust precisely when coercions occur.
|
||||||
|
|
||||||
use check::{FnCtxt};
|
use check::FnCtxt;
|
||||||
|
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace};
|
use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace};
|
||||||
|
@ -79,7 +79,7 @@ use std::cell::RefCell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
struct Coerce<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||||
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
|
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
|
||||||
origin: TypeOrigin,
|
origin: TypeOrigin,
|
||||||
use_lub: bool,
|
use_lub: bool,
|
||||||
|
@ -102,7 +102,7 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
|
||||||
(hir::MutMutable, hir::MutMutable) |
|
(hir::MutMutable, hir::MutMutable) |
|
||||||
(hir::MutImmutable, hir::MutImmutable) |
|
(hir::MutImmutable, hir::MutImmutable) |
|
||||||
(hir::MutMutable, hir::MutImmutable) => Ok(()),
|
(hir::MutMutable, hir::MutImmutable) => Ok(()),
|
||||||
(hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability)
|
(hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
fcx: fcx,
|
fcx: fcx,
|
||||||
origin: origin,
|
origin: origin,
|
||||||
use_lub: false,
|
use_lub: false,
|
||||||
unsizing_obligations: RefCell::new(vec![])
|
unsizing_obligations: RefCell::new(vec![]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,21 +144,18 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
|
|
||||||
/// Synthesize an identity adjustment.
|
/// Synthesize an identity adjustment.
|
||||||
fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> {
|
fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> {
|
||||||
Ok((ty, AdjustDerefRef(AutoDerefRef {
|
Ok((ty,
|
||||||
autoderefs: 0,
|
AdjustDerefRef(AutoDerefRef {
|
||||||
autoref: None,
|
autoderefs: 0,
|
||||||
unsize: None
|
autoref: None,
|
||||||
})))
|
unsize: None,
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn coerce<'a, E, I>(&self,
|
fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx>
|
||||||
exprs: &E,
|
|
||||||
a: Ty<'tcx>,
|
|
||||||
b: Ty<'tcx>)
|
|
||||||
-> CoerceResult<'tcx>
|
|
||||||
// FIXME(eddyb) use copyable iterators when that becomes ergonomic.
|
|
||||||
where E: Fn() -> I,
|
where E: Fn() -> I,
|
||||||
I: IntoIterator<Item=&'a hir::Expr> {
|
I: IntoIterator<Item = &'a hir::Expr>
|
||||||
|
{
|
||||||
|
|
||||||
let a = self.shallow_resolve(a);
|
let a = self.shallow_resolve(a);
|
||||||
debug!("Coerce.tys({:?} => {:?})", a, b);
|
debug!("Coerce.tys({:?} => {:?})", a, b);
|
||||||
|
@ -223,9 +220,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
r_b: &'tcx ty::Region,
|
r_b: &'tcx ty::Region,
|
||||||
mt_b: TypeAndMut<'tcx>)
|
mt_b: TypeAndMut<'tcx>)
|
||||||
-> CoerceResult<'tcx>
|
-> CoerceResult<'tcx>
|
||||||
// FIXME(eddyb) use copyable iterators when that becomes ergonomic.
|
|
||||||
where E: Fn() -> I,
|
where E: Fn() -> I,
|
||||||
I: IntoIterator<Item=&'a hir::Expr>
|
I: IntoIterator<Item = &'a hir::Expr>
|
||||||
{
|
{
|
||||||
|
|
||||||
debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b);
|
debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b);
|
||||||
|
@ -241,7 +237,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
|
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
|
||||||
(r_a, mt_a)
|
(r_a, mt_a)
|
||||||
}
|
}
|
||||||
_ => return self.unify_and_identity(a, b)
|
_ => return self.unify_and_identity(a, b),
|
||||||
};
|
};
|
||||||
|
|
||||||
let span = self.origin.span();
|
let span = self.origin.span();
|
||||||
|
@ -255,7 +251,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
if autoderefs == 0 {
|
if autoderefs == 0 {
|
||||||
// Don't let this pass, otherwise it would cause
|
// Don't let this pass, otherwise it would cause
|
||||||
// &T to autoref to &&T.
|
// &T to autoref to &&T.
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point, we have deref'd `a` to `referent_ty`. So
|
// At this point, we have deref'd `a` to `referent_ty`. So
|
||||||
|
@ -333,19 +329,24 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
} else if autoderefs == 1 {
|
} else if autoderefs == 1 {
|
||||||
r_a // [3] above
|
r_a // [3] above
|
||||||
} else {
|
} else {
|
||||||
if r_borrow_var.is_none() { // create var lazilly, at most once
|
if r_borrow_var.is_none() {
|
||||||
|
// create var lazilly, at most once
|
||||||
let coercion = Coercion(span);
|
let coercion = Coercion(span);
|
||||||
let r = self.next_region_var(coercion);
|
let r = self.next_region_var(coercion);
|
||||||
r_borrow_var = Some(r); // [4] above
|
r_borrow_var = Some(r); // [4] above
|
||||||
}
|
}
|
||||||
r_borrow_var.unwrap()
|
r_borrow_var.unwrap()
|
||||||
};
|
};
|
||||||
let derefd_ty_a = self.tcx.mk_ref(r, TypeAndMut {
|
let derefd_ty_a = self.tcx.mk_ref(r,
|
||||||
ty: referent_ty,
|
TypeAndMut {
|
||||||
mutbl: mt_b.mutbl // [1] above
|
ty: referent_ty,
|
||||||
});
|
mutbl: mt_b.mutbl, // [1] above
|
||||||
|
});
|
||||||
match self.unify(derefd_ty_a, b) {
|
match self.unify(derefd_ty_a, b) {
|
||||||
Ok(ty) => { success = Some((ty, autoderefs)); break },
|
Ok(ty) => {
|
||||||
|
success = Some((ty, autoderefs));
|
||||||
|
break;
|
||||||
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if first_error.is_none() {
|
if first_error.is_none() {
|
||||||
first_error = Some(err);
|
first_error = Some(err);
|
||||||
|
@ -391,29 +392,27 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
let r_borrow = match ty.sty {
|
let r_borrow = match ty.sty {
|
||||||
ty::TyRef(r_borrow, _) => r_borrow,
|
ty::TyRef(r_borrow, _) => r_borrow,
|
||||||
_ => span_bug!(span, "expected a ref type, got {:?}", ty)
|
_ => span_bug!(span, "expected a ref type, got {:?}", ty),
|
||||||
};
|
};
|
||||||
let autoref = Some(AutoPtr(r_borrow, mt_b.mutbl));
|
let autoref = Some(AutoPtr(r_borrow, mt_b.mutbl));
|
||||||
debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}",
|
debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}",
|
||||||
ty, autoderefs, autoref);
|
ty,
|
||||||
Ok((ty, AdjustDerefRef(AutoDerefRef {
|
autoderefs,
|
||||||
autoderefs: autoderefs,
|
autoref);
|
||||||
autoref: autoref,
|
Ok((ty,
|
||||||
unsize: None
|
AdjustDerefRef(AutoDerefRef {
|
||||||
})))
|
autoderefs: autoderefs,
|
||||||
|
autoref: autoref,
|
||||||
|
unsize: None,
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// &[T; n] or &mut [T; n] -> &[T]
|
// &[T; n] or &mut [T; n] -> &[T]
|
||||||
// or &mut [T; n] -> &mut [T]
|
// or &mut [T; n] -> &mut [T]
|
||||||
// or &Concrete -> &Trait, etc.
|
// or &Concrete -> &Trait, etc.
|
||||||
fn coerce_unsized(&self,
|
fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tcx> {
|
||||||
source: Ty<'tcx>,
|
debug!("coerce_unsized(source={:?}, target={:?})", source, target);
|
||||||
target: Ty<'tcx>)
|
|
||||||
-> CoerceResult<'tcx> {
|
|
||||||
debug!("coerce_unsized(source={:?}, target={:?})",
|
|
||||||
source,
|
|
||||||
target);
|
|
||||||
|
|
||||||
let traits = (self.tcx.lang_items.unsize_trait(),
|
let traits = (self.tcx.lang_items.unsize_trait(),
|
||||||
self.tcx.lang_items.coerce_unsized_trait());
|
self.tcx.lang_items.coerce_unsized_trait());
|
||||||
|
@ -442,7 +441,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
|
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
|
||||||
(mt_a.ty, Some(AutoUnsafe(mt_b.mutbl)))
|
(mt_a.ty, Some(AutoUnsafe(mt_b.mutbl)))
|
||||||
}
|
}
|
||||||
_ => (source, None)
|
_ => (source, None),
|
||||||
};
|
};
|
||||||
let source = source.adjust_for_autoref(self.tcx, reborrow);
|
let source = source.adjust_for_autoref(self.tcx, reborrow);
|
||||||
|
|
||||||
|
@ -454,11 +453,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
|
|
||||||
// Create an obligation for `Source: CoerceUnsized<Target>`.
|
// Create an obligation for `Source: CoerceUnsized<Target>`.
|
||||||
let cause = ObligationCause::misc(self.origin.span(), self.body_id);
|
let cause = ObligationCause::misc(self.origin.span(), self.body_id);
|
||||||
queue.push_back(self.tcx.predicate_for_trait_def(cause,
|
queue.push_back(self.tcx
|
||||||
coerce_unsized_did,
|
.predicate_for_trait_def(cause, coerce_unsized_did, 0, source, &[target]));
|
||||||
0,
|
|
||||||
source,
|
|
||||||
&[target]));
|
|
||||||
|
|
||||||
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
|
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
|
||||||
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
|
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
|
||||||
|
@ -466,10 +462,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
let traits = [coerce_unsized_did, unsize_did];
|
let traits = [coerce_unsized_did, unsize_did];
|
||||||
while let Some(obligation) = queue.pop_front() {
|
while let Some(obligation) = queue.pop_front() {
|
||||||
debug!("coerce_unsized resolve step: {:?}", obligation);
|
debug!("coerce_unsized resolve step: {:?}", obligation);
|
||||||
let trait_ref = match obligation.predicate {
|
let trait_ref = match obligation.predicate {
|
||||||
ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {
|
ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(),
|
||||||
tr.clone()
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
leftover_predicates.push(obligation);
|
leftover_predicates.push(obligation);
|
||||||
continue;
|
continue;
|
||||||
|
@ -477,7 +471,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
};
|
};
|
||||||
match selcx.select(&obligation.with(trait_ref)) {
|
match selcx.select(&obligation.with(trait_ref)) {
|
||||||
// Uncertain or unimplemented.
|
// Uncertain or unimplemented.
|
||||||
Ok(None) | Err(traits::Unimplemented) => {
|
Ok(None) |
|
||||||
|
Err(traits::Unimplemented) => {
|
||||||
debug!("coerce_unsized: early return - can't prove obligation");
|
debug!("coerce_unsized: early return - can't prove obligation");
|
||||||
return Err(TypeError::Mismatch);
|
return Err(TypeError::Mismatch);
|
||||||
}
|
}
|
||||||
|
@ -503,22 +498,20 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
let adjustment = AutoDerefRef {
|
let adjustment = AutoDerefRef {
|
||||||
autoderefs: if reborrow.is_some() { 1 } else { 0 },
|
autoderefs: if reborrow.is_some() { 1 } else { 0 },
|
||||||
autoref: reborrow,
|
autoref: reborrow,
|
||||||
unsize: Some(target)
|
unsize: Some(target),
|
||||||
};
|
};
|
||||||
debug!("Success, coerced with {:?}", adjustment);
|
debug!("Success, coerced with {:?}", adjustment);
|
||||||
Ok((target, AdjustDerefRef(adjustment)))
|
Ok((target, AdjustDerefRef(adjustment)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn coerce_from_fn_pointer(&self,
|
fn coerce_from_fn_pointer(&self,
|
||||||
a: Ty<'tcx>,
|
a: Ty<'tcx>,
|
||||||
fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
|
fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
|
||||||
b: Ty<'tcx>)
|
b: Ty<'tcx>)
|
||||||
-> CoerceResult<'tcx>
|
-> CoerceResult<'tcx> {
|
||||||
{
|
//! Attempts to coerce from the type of a Rust function item
|
||||||
/*!
|
//! into a closure or a `proc`.
|
||||||
* Attempts to coerce from the type of a Rust function item
|
//!
|
||||||
* into a closure or a `proc`.
|
|
||||||
*/
|
|
||||||
|
|
||||||
let b = self.shallow_resolve(b);
|
let b = self.shallow_resolve(b);
|
||||||
debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
|
debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
|
||||||
|
@ -527,9 +520,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
|
match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
|
||||||
(hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
|
(hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
|
||||||
let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
|
let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
|
||||||
return self.unify_and_identity(unsafe_a, b).map(|(ty, _)| {
|
return self.unify_and_identity(unsafe_a, b)
|
||||||
(ty, AdjustUnsafeFnPointer)
|
.map(|(ty, _)| (ty, AdjustUnsafeFnPointer));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -542,10 +534,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
|
fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
|
||||||
b: Ty<'tcx>)
|
b: Ty<'tcx>)
|
||||||
-> CoerceResult<'tcx> {
|
-> CoerceResult<'tcx> {
|
||||||
/*!
|
//! Attempts to coerce from the type of a Rust function item
|
||||||
* Attempts to coerce from the type of a Rust function item
|
//! into a closure or a `proc`.
|
||||||
* into a closure or a `proc`.
|
//!
|
||||||
*/
|
|
||||||
|
|
||||||
let b = self.shallow_resolve(b);
|
let b = self.shallow_resolve(b);
|
||||||
debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
|
debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
|
||||||
|
@ -553,11 +544,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
match b.sty {
|
match b.sty {
|
||||||
ty::TyFnPtr(_) => {
|
ty::TyFnPtr(_) => {
|
||||||
let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a);
|
let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a);
|
||||||
self.unify_and_identity(a_fn_pointer, b).map(|(ty, _)| {
|
self.unify_and_identity(a_fn_pointer, b).map(|(ty, _)| (ty, AdjustReifyFnPointer))
|
||||||
(ty, AdjustReifyFnPointer)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
_ => self.unify_and_identity(a, b)
|
_ => self.unify_and_identity(a, b),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,9 +555,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
b: Ty<'tcx>,
|
b: Ty<'tcx>,
|
||||||
mutbl_b: hir::Mutability)
|
mutbl_b: hir::Mutability)
|
||||||
-> CoerceResult<'tcx> {
|
-> CoerceResult<'tcx> {
|
||||||
debug!("coerce_unsafe_ptr(a={:?}, b={:?})",
|
debug!("coerce_unsafe_ptr(a={:?}, b={:?})", a, b);
|
||||||
a,
|
|
||||||
b);
|
|
||||||
|
|
||||||
let (is_ref, mt_a) = match a.sty {
|
let (is_ref, mt_a) = match a.sty {
|
||||||
ty::TyRef(_, mt) => (true, mt),
|
ty::TyRef(_, mt) => (true, mt),
|
||||||
|
@ -579,24 +566,28 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check that the types which they point at are compatible.
|
// Check that the types which they point at are compatible.
|
||||||
let a_unsafe = self.tcx.mk_ptr(ty::TypeAndMut{ mutbl: mutbl_b, ty: mt_a.ty });
|
let a_unsafe = self.tcx.mk_ptr(ty::TypeAndMut {
|
||||||
|
mutbl: mutbl_b,
|
||||||
|
ty: mt_a.ty,
|
||||||
|
});
|
||||||
let (ty, noop) = self.unify_and_identity(a_unsafe, b)?;
|
let (ty, noop) = self.unify_and_identity(a_unsafe, b)?;
|
||||||
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
|
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
|
||||||
|
|
||||||
// Although references and unsafe ptrs have the same
|
// Although references and unsafe ptrs have the same
|
||||||
// representation, we still register an AutoDerefRef so that
|
// representation, we still register an AutoDerefRef so that
|
||||||
// regionck knows that the region for `a` must be valid here.
|
// regionck knows that the region for `a` must be valid here.
|
||||||
Ok((ty, if is_ref {
|
Ok((ty,
|
||||||
AdjustDerefRef(AutoDerefRef {
|
if is_ref {
|
||||||
autoderefs: 1,
|
AdjustDerefRef(AutoDerefRef {
|
||||||
autoref: Some(AutoUnsafe(mutbl_b)),
|
autoderefs: 1,
|
||||||
unsize: None
|
autoref: Some(AutoUnsafe(mutbl_b)),
|
||||||
})
|
unsize: None,
|
||||||
} else if mt_a.mutbl != mutbl_b {
|
})
|
||||||
AdjustMutToConstPointer
|
} else if mt_a.mutbl != mutbl_b {
|
||||||
} else {
|
AdjustMutToConstPointer
|
||||||
noop
|
} else {
|
||||||
}))
|
noop
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,7 +597,8 @@ fn apply<'a, 'b, 'gcx, 'tcx, E, I>(coerce: &mut Coerce<'a, 'gcx, 'tcx>,
|
||||||
b: Ty<'tcx>)
|
b: Ty<'tcx>)
|
||||||
-> CoerceResult<'tcx>
|
-> CoerceResult<'tcx>
|
||||||
where E: Fn() -> I,
|
where E: Fn() -> I,
|
||||||
I: IntoIterator<Item=&'b hir::Expr> {
|
I: IntoIterator<Item = &'b hir::Expr>
|
||||||
|
{
|
||||||
|
|
||||||
let (ty, adjustment) = indent(|| coerce.coerce(exprs, a, b))?;
|
let (ty, adjustment) = indent(|| coerce.coerce(exprs, a, b))?;
|
||||||
|
|
||||||
|
@ -638,12 +630,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span));
|
let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span));
|
||||||
self.commit_if_ok(|_| {
|
self.commit_if_ok(|_| {
|
||||||
let (ty, adjustment) =
|
let (ty, adjustment) = apply(&mut coerce, &|| Some(expr), source, target)?;
|
||||||
apply(&mut coerce, &|| Some(expr), source, target)?;
|
|
||||||
if !adjustment.is_identity() {
|
if !adjustment.is_identity() {
|
||||||
debug!("Success, coerced with {:?}", adjustment);
|
debug!("Success, coerced with {:?}", adjustment);
|
||||||
match self.tables.borrow().adjustments.get(&expr.id) {
|
match self.tables.borrow().adjustments.get(&expr.id) {
|
||||||
None | Some(&AdjustNeverToAny(..)) => (),
|
None |
|
||||||
|
Some(&AdjustNeverToAny(..)) => (),
|
||||||
_ => bug!("expr already has an adjustment on it!"),
|
_ => bug!("expr already has an adjustment on it!"),
|
||||||
};
|
};
|
||||||
self.write_adjustment(expr.id, adjustment);
|
self.write_adjustment(expr.id, adjustment);
|
||||||
|
@ -662,9 +654,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
new: &'b hir::Expr,
|
new: &'b hir::Expr,
|
||||||
new_ty: Ty<'tcx>)
|
new_ty: Ty<'tcx>)
|
||||||
-> RelateResult<'tcx, Ty<'tcx>>
|
-> RelateResult<'tcx, Ty<'tcx>>
|
||||||
// FIXME(eddyb) use copyable iterators when that becomes ergonomic.
|
|
||||||
where E: Fn() -> I,
|
where E: Fn() -> I,
|
||||||
I: IntoIterator<Item=&'b hir::Expr> {
|
I: IntoIterator<Item = &'b hir::Expr>
|
||||||
|
{
|
||||||
|
|
||||||
let prev_ty = self.resolve_type_vars_with_obligations(prev_ty);
|
let prev_ty = self.resolve_type_vars_with_obligations(prev_ty);
|
||||||
let new_ty = self.resolve_type_vars_with_obligations(new_ty);
|
let new_ty = self.resolve_type_vars_with_obligations(new_ty);
|
||||||
|
@ -675,8 +667,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// Special-case that coercion alone cannot handle:
|
// Special-case that coercion alone cannot handle:
|
||||||
// Two function item types of differing IDs or Substs.
|
// Two function item types of differing IDs or Substs.
|
||||||
match (&prev_ty.sty, &new_ty.sty) {
|
match (&prev_ty.sty, &new_ty.sty) {
|
||||||
(&ty::TyFnDef(a_def_id, a_substs, a_fty),
|
(&ty::TyFnDef(a_def_id, a_substs, a_fty), &ty::TyFnDef(b_def_id, b_substs, b_fty)) => {
|
||||||
&ty::TyFnDef(b_def_id, b_substs, b_fty)) => {
|
|
||||||
// The signature must always match.
|
// The signature must always match.
|
||||||
let fty = self.lub(true, trace.clone(), &a_fty, &b_fty)
|
let fty = self.lub(true, trace.clone(), &a_fty, &b_fty)
|
||||||
.map(|InferOk { value, obligations }| {
|
.map(|InferOk { value, obligations }| {
|
||||||
|
@ -720,9 +711,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// but only if the new expression has no coercion already applied to it.
|
// but only if the new expression has no coercion already applied to it.
|
||||||
let mut first_error = None;
|
let mut first_error = None;
|
||||||
if !self.tables.borrow().adjustments.contains_key(&new.id) {
|
if !self.tables.borrow().adjustments.contains_key(&new.id) {
|
||||||
let result = self.commit_if_ok(|_| {
|
let result = self.commit_if_ok(|_| apply(&mut coerce, &|| Some(new), new_ty, prev_ty));
|
||||||
apply(&mut coerce, &|| Some(new), new_ty, prev_ty)
|
|
||||||
});
|
|
||||||
match result {
|
match result {
|
||||||
Ok((ty, adjustment)) => {
|
Ok((ty, adjustment)) => {
|
||||||
if !adjustment.is_identity() {
|
if !adjustment.is_identity() {
|
||||||
|
@ -730,7 +719,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
return Ok(ty);
|
return Ok(ty);
|
||||||
}
|
}
|
||||||
Err(e) => first_error = Some(e)
|
Err(e) => first_error = Some(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,20 +728,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// previous expressions, other than noop reborrows (ignoring lifetimes).
|
// previous expressions, other than noop reborrows (ignoring lifetimes).
|
||||||
for expr in exprs() {
|
for expr in exprs() {
|
||||||
let noop = match self.tables.borrow().adjustments.get(&expr.id) {
|
let noop = match self.tables.borrow().adjustments.get(&expr.id) {
|
||||||
Some(&AdjustDerefRef(AutoDerefRef {
|
Some(&AdjustDerefRef(AutoDerefRef { autoderefs: 1,
|
||||||
autoderefs: 1,
|
autoref: Some(AutoPtr(_, mutbl_adj)),
|
||||||
autoref: Some(AutoPtr(_, mutbl_adj)),
|
unsize: None })) => {
|
||||||
unsize: None
|
match self.node_ty(expr.id).sty {
|
||||||
})) => match self.node_ty(expr.id).sty {
|
ty::TyRef(_, mt_orig) => {
|
||||||
ty::TyRef(_, mt_orig) => {
|
// Reborrow that we can safely ignore.
|
||||||
// Reborrow that we can safely ignore.
|
mutbl_adj == mt_orig.mutbl
|
||||||
mutbl_adj == mt_orig.mutbl
|
}
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
_ => false
|
}
|
||||||
},
|
|
||||||
Some(&AdjustNeverToAny(_)) => true,
|
Some(&AdjustNeverToAny(_)) => true,
|
||||||
Some(_) => false,
|
Some(_) => false,
|
||||||
None => true
|
None => true,
|
||||||
};
|
};
|
||||||
|
|
||||||
if !noop {
|
if !noop {
|
||||||
|
|
|
@ -40,8 +40,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
trait_m: &ty::Method<'tcx>,
|
trait_m: &ty::Method<'tcx>,
|
||||||
impl_trait_ref: &ty::TraitRef<'tcx>,
|
impl_trait_ref: &ty::TraitRef<'tcx>,
|
||||||
trait_item_span: Option<Span>) {
|
trait_item_span: Option<Span>) {
|
||||||
debug!("compare_impl_method(impl_trait_ref={:?})",
|
debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
|
||||||
impl_trait_ref);
|
|
||||||
|
|
||||||
debug!("compare_impl_method: impl_trait_ref (liberated) = {:?}",
|
debug!("compare_impl_method: impl_trait_ref (liberated) = {:?}",
|
||||||
impl_trait_ref);
|
impl_trait_ref);
|
||||||
|
@ -58,34 +57,36 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
// inscrutable, particularly for cases where one method has no
|
// inscrutable, particularly for cases where one method has no
|
||||||
// self.
|
// self.
|
||||||
match (&trait_m.explicit_self, &impl_m.explicit_self) {
|
match (&trait_m.explicit_self, &impl_m.explicit_self) {
|
||||||
(&ty::ExplicitSelfCategory::Static,
|
(&ty::ExplicitSelfCategory::Static, &ty::ExplicitSelfCategory::Static) => {}
|
||||||
&ty::ExplicitSelfCategory::Static) => {}
|
|
||||||
(&ty::ExplicitSelfCategory::Static, _) => {
|
(&ty::ExplicitSelfCategory::Static, _) => {
|
||||||
let mut err = struct_span_err!(tcx.sess, impl_m_span, E0185,
|
let mut err = struct_span_err!(tcx.sess,
|
||||||
"method `{}` has a `{}` declaration in the impl, \
|
impl_m_span,
|
||||||
but not in the trait",
|
E0185,
|
||||||
trait_m.name,
|
"method `{}` has a `{}` declaration in the impl, but \
|
||||||
impl_m.explicit_self);
|
not in the trait",
|
||||||
err.span_label(impl_m_span, &format!("`{}` used in impl",
|
trait_m.name,
|
||||||
impl_m.explicit_self));
|
impl_m.explicit_self);
|
||||||
|
err.span_label(impl_m_span,
|
||||||
|
&format!("`{}` used in impl", impl_m.explicit_self));
|
||||||
if let Some(span) = tcx.map.span_if_local(trait_m.def_id) {
|
if let Some(span) = tcx.map.span_if_local(trait_m.def_id) {
|
||||||
err.span_label(span, &format!("trait declared without `{}`",
|
err.span_label(span,
|
||||||
impl_m.explicit_self));
|
&format!("trait declared without `{}`", impl_m.explicit_self));
|
||||||
}
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
(_, &ty::ExplicitSelfCategory::Static) => {
|
(_, &ty::ExplicitSelfCategory::Static) => {
|
||||||
let mut err = struct_span_err!(tcx.sess, impl_m_span, E0186,
|
let mut err = struct_span_err!(tcx.sess,
|
||||||
"method `{}` has a `{}` declaration in the trait, \
|
impl_m_span,
|
||||||
but not in the impl",
|
E0186,
|
||||||
trait_m.name,
|
"method `{}` has a `{}` declaration in the trait, but \
|
||||||
trait_m.explicit_self);
|
not in the impl",
|
||||||
err.span_label(impl_m_span, &format!("expected `{}` in impl",
|
trait_m.name,
|
||||||
trait_m.explicit_self));
|
trait_m.explicit_self);
|
||||||
|
err.span_label(impl_m_span,
|
||||||
|
&format!("expected `{}` in impl", trait_m.explicit_self));
|
||||||
if let Some(span) = tcx.map.span_if_local(trait_m.def_id) {
|
if let Some(span) = tcx.map.span_if_local(trait_m.def_id) {
|
||||||
err.span_label(span, & format!("`{}` used in trait",
|
err.span_label(span, &format!("`{}` used in trait", trait_m.explicit_self));
|
||||||
trait_m.explicit_self));
|
|
||||||
}
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
return;
|
return;
|
||||||
|
@ -107,17 +108,23 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
impl_m_span
|
impl_m_span
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => bug!("{:?} is not a method", impl_m)
|
_ => bug!("{:?} is not a method", impl_m),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut err = struct_span_err!(tcx.sess, span, E0049,
|
let mut err = struct_span_err!(tcx.sess,
|
||||||
"method `{}` has {} type parameter{} \
|
span,
|
||||||
but its trait declaration has {} type parameter{}",
|
E0049,
|
||||||
trait_m.name,
|
"method `{}` has {} type parameter{} but its trait \
|
||||||
num_impl_m_type_params,
|
declaration has {} type parameter{}",
|
||||||
if num_impl_m_type_params == 1 {""} else {"s"},
|
trait_m.name,
|
||||||
num_trait_m_type_params,
|
num_impl_m_type_params,
|
||||||
if num_trait_m_type_params == 1 {""} else {"s"});
|
if num_impl_m_type_params == 1 { "" } else { "s" },
|
||||||
|
num_trait_m_type_params,
|
||||||
|
if num_trait_m_type_params == 1 {
|
||||||
|
""
|
||||||
|
} else {
|
||||||
|
"s"
|
||||||
|
});
|
||||||
|
|
||||||
let mut suffix = None;
|
let mut suffix = None;
|
||||||
|
|
||||||
|
@ -154,18 +161,17 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
let trait_span = if let Some(trait_id) = trait_m_node_id {
|
let trait_span = if let Some(trait_id) = trait_m_node_id {
|
||||||
match tcx.map.expect_trait_item(trait_id).node {
|
match tcx.map.expect_trait_item(trait_id).node {
|
||||||
TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
|
TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
|
||||||
if let Some(arg) = trait_m_sig.decl.inputs.get(
|
if let Some(arg) = trait_m_sig.decl.inputs.get(if trait_number_args > 0 {
|
||||||
if trait_number_args > 0 {
|
trait_number_args - 1
|
||||||
trait_number_args - 1
|
} else {
|
||||||
} else {
|
0
|
||||||
0
|
}) {
|
||||||
}) {
|
|
||||||
Some(arg.pat.span)
|
Some(arg.pat.span)
|
||||||
} else {
|
} else {
|
||||||
trait_item_span
|
trait_item_span
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => bug!("{:?} is not a method", impl_m)
|
_ => bug!("{:?} is not a method", impl_m),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
trait_item_span
|
trait_item_span
|
||||||
|
@ -173,27 +179,28 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
|
let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
|
||||||
let impl_span = match tcx.map.expect_impl_item(impl_m_node_id).node {
|
let impl_span = match tcx.map.expect_impl_item(impl_m_node_id).node {
|
||||||
ImplItemKind::Method(ref impl_m_sig, _) => {
|
ImplItemKind::Method(ref impl_m_sig, _) => {
|
||||||
if let Some(arg) = impl_m_sig.decl.inputs.get(
|
if let Some(arg) = impl_m_sig.decl.inputs.get(if impl_number_args > 0 {
|
||||||
if impl_number_args > 0 {
|
impl_number_args - 1
|
||||||
impl_number_args - 1
|
} else {
|
||||||
} else {
|
0
|
||||||
0
|
}) {
|
||||||
}) {
|
|
||||||
arg.pat.span
|
arg.pat.span
|
||||||
} else {
|
} else {
|
||||||
impl_m_span
|
impl_m_span
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => bug!("{:?} is not a method", impl_m)
|
_ => bug!("{:?} is not a method", impl_m),
|
||||||
};
|
};
|
||||||
let mut err = struct_span_err!(tcx.sess, impl_span, E0050,
|
let mut err = struct_span_err!(tcx.sess,
|
||||||
"method `{}` has {} parameter{} \
|
impl_span,
|
||||||
but the declaration in trait `{}` has {}",
|
E0050,
|
||||||
trait_m.name,
|
"method `{}` has {} parameter{} but the declaration in \
|
||||||
impl_number_args,
|
trait `{}` has {}",
|
||||||
if impl_number_args == 1 {""} else {"s"},
|
trait_m.name,
|
||||||
tcx.item_path_str(trait_m.def_id),
|
impl_number_args,
|
||||||
trait_number_args);
|
if impl_number_args == 1 { "" } else { "s" },
|
||||||
|
tcx.item_path_str(trait_m.def_id),
|
||||||
|
trait_number_args);
|
||||||
if let Some(trait_span) = trait_span {
|
if let Some(trait_span) = trait_span {
|
||||||
err.span_label(trait_span,
|
err.span_label(trait_span,
|
||||||
&format!("trait requires {}",
|
&format!("trait requires {}",
|
||||||
|
@ -210,7 +217,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
} else {
|
} else {
|
||||||
format!("{} parameter", trait_number_args)
|
format!("{} parameter", trait_number_args)
|
||||||
},
|
},
|
||||||
impl_number_args));
|
impl_number_args));
|
||||||
err.emit();
|
err.emit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -287,9 +294,10 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
let impl_to_skol_substs = &impl_param_env.free_substs;
|
let impl_to_skol_substs = &impl_param_env.free_substs;
|
||||||
|
|
||||||
// Create mapping from trait to skolemized.
|
// Create mapping from trait to skolemized.
|
||||||
let trait_to_skol_substs =
|
let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx,
|
||||||
impl_to_skol_substs.rebase_onto(tcx, impl_m.container_id(),
|
impl_m.container_id(),
|
||||||
trait_to_impl_substs.subst(tcx, impl_to_skol_substs));
|
trait_to_impl_substs.subst(tcx,
|
||||||
|
impl_to_skol_substs));
|
||||||
debug!("compare_impl_method: trait_to_skol_substs={:?}",
|
debug!("compare_impl_method: trait_to_skol_substs={:?}",
|
||||||
trait_to_skol_substs);
|
trait_to_skol_substs);
|
||||||
|
|
||||||
|
@ -325,31 +333,28 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
//
|
//
|
||||||
// We then register the obligations from the impl_m and check to see
|
// We then register the obligations from the impl_m and check to see
|
||||||
// if all constraints hold.
|
// if all constraints hold.
|
||||||
hybrid_preds.predicates.extend(
|
hybrid_preds.predicates
|
||||||
trait_m.predicates.instantiate_own(tcx, trait_to_skol_substs).predicates);
|
.extend(trait_m.predicates.instantiate_own(tcx, trait_to_skol_substs).predicates);
|
||||||
|
|
||||||
// Construct trait parameter environment and then shift it into the skolemized viewpoint.
|
// 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 key step here is to update the caller_bounds's predicates to be
|
||||||
// the new hybrid bounds we computed.
|
// the new hybrid bounds we computed.
|
||||||
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id);
|
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.predicates);
|
let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates);
|
||||||
let trait_param_env = traits::normalize_param_env_or_error(tcx,
|
let trait_param_env =
|
||||||
trait_param_env,
|
traits::normalize_param_env_or_error(tcx, trait_param_env, normalize_cause.clone());
|
||||||
normalize_cause.clone());
|
|
||||||
// FIXME(@jroesch) this seems ugly, but is a temporary change
|
// FIXME(@jroesch) this seems ugly, but is a temporary change
|
||||||
infcx.parameter_environment = trait_param_env;
|
infcx.parameter_environment = trait_param_env;
|
||||||
|
|
||||||
debug!("compare_impl_method: caller_bounds={:?}",
|
debug!("compare_impl_method: caller_bounds={:?}",
|
||||||
infcx.parameter_environment.caller_bounds);
|
infcx.parameter_environment.caller_bounds);
|
||||||
|
|
||||||
let mut selcx = traits::SelectionContext::new(&infcx);
|
let mut selcx = traits::SelectionContext::new(&infcx);
|
||||||
|
|
||||||
let impl_m_own_bounds = impl_m.predicates.instantiate_own(tcx, impl_to_skol_substs);
|
let impl_m_own_bounds = impl_m.predicates.instantiate_own(tcx, impl_to_skol_substs);
|
||||||
let (impl_m_own_bounds, _) =
|
let (impl_m_own_bounds, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
|
||||||
infcx.replace_late_bound_regions_with_fresh_var(
|
infer::HigherRankedType,
|
||||||
impl_m_span,
|
&ty::Binder(impl_m_own_bounds.predicates));
|
||||||
infer::HigherRankedType,
|
|
||||||
&ty::Binder(impl_m_own_bounds.predicates));
|
|
||||||
for predicate in impl_m_own_bounds {
|
for predicate in impl_m_own_bounds {
|
||||||
let traits::Normalized { value: predicate, .. } =
|
let traits::Normalized { value: predicate, .. } =
|
||||||
traits::normalize(&mut selcx, normalize_cause.clone(), &predicate);
|
traits::normalize(&mut selcx, normalize_cause.clone(), &predicate);
|
||||||
|
@ -357,7 +362,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
let cause = traits::ObligationCause {
|
let cause = traits::ObligationCause {
|
||||||
span: impl_m_span,
|
span: impl_m_span,
|
||||||
body_id: impl_m_body_id,
|
body_id: impl_m_body_id,
|
||||||
code: traits::ObligationCauseCode::CompareImplMethodObligation
|
code: traits::ObligationCauseCode::CompareImplMethodObligation,
|
||||||
};
|
};
|
||||||
|
|
||||||
fulfillment_cx.register_predicate_obligation(
|
fulfillment_cx.register_predicate_obligation(
|
||||||
|
@ -382,40 +387,34 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
let origin = TypeOrigin::MethodCompatCheck(impl_m_span);
|
let origin = TypeOrigin::MethodCompatCheck(impl_m_span);
|
||||||
|
|
||||||
let (impl_sig, _) =
|
let (impl_sig, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
|
||||||
infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
|
infer::HigherRankedType,
|
||||||
infer::HigherRankedType,
|
&impl_m.fty.sig);
|
||||||
&impl_m.fty.sig);
|
let impl_sig = impl_sig.subst(tcx, impl_to_skol_substs);
|
||||||
let impl_sig =
|
let impl_sig = assoc::normalize_associated_types_in(&infcx,
|
||||||
impl_sig.subst(tcx, impl_to_skol_substs);
|
&mut fulfillment_cx,
|
||||||
let impl_sig =
|
impl_m_span,
|
||||||
assoc::normalize_associated_types_in(&infcx,
|
impl_m_body_id,
|
||||||
&mut fulfillment_cx,
|
&impl_sig);
|
||||||
impl_m_span,
|
|
||||||
impl_m_body_id,
|
|
||||||
&impl_sig);
|
|
||||||
let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
|
let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
|
||||||
unsafety: impl_m.fty.unsafety,
|
unsafety: impl_m.fty.unsafety,
|
||||||
abi: impl_m.fty.abi,
|
abi: impl_m.fty.abi,
|
||||||
sig: ty::Binder(impl_sig.clone())
|
sig: ty::Binder(impl_sig.clone()),
|
||||||
}));
|
}));
|
||||||
debug!("compare_impl_method: impl_fty={:?}", impl_fty);
|
debug!("compare_impl_method: impl_fty={:?}", impl_fty);
|
||||||
|
|
||||||
let trait_sig = tcx.liberate_late_bound_regions(
|
let trait_sig = tcx.liberate_late_bound_regions(infcx.parameter_environment.free_id_outlive,
|
||||||
infcx.parameter_environment.free_id_outlive,
|
&trait_m.fty.sig);
|
||||||
&trait_m.fty.sig);
|
let trait_sig = trait_sig.subst(tcx, trait_to_skol_substs);
|
||||||
let trait_sig =
|
let trait_sig = assoc::normalize_associated_types_in(&infcx,
|
||||||
trait_sig.subst(tcx, trait_to_skol_substs);
|
&mut fulfillment_cx,
|
||||||
let trait_sig =
|
impl_m_span,
|
||||||
assoc::normalize_associated_types_in(&infcx,
|
impl_m_body_id,
|
||||||
&mut fulfillment_cx,
|
&trait_sig);
|
||||||
impl_m_span,
|
|
||||||
impl_m_body_id,
|
|
||||||
&trait_sig);
|
|
||||||
let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
|
let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
|
||||||
unsafety: trait_m.fty.unsafety,
|
unsafety: trait_m.fty.unsafety,
|
||||||
abi: trait_m.fty.abi,
|
abi: trait_m.fty.abi,
|
||||||
sig: ty::Binder(trait_sig.clone())
|
sig: ty::Binder(trait_sig.clone()),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
debug!("compare_impl_method: trait_fty={:?}", trait_fty);
|
debug!("compare_impl_method: trait_fty={:?}", trait_fty);
|
||||||
|
@ -425,36 +424,39 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
impl_fty,
|
impl_fty,
|
||||||
trait_fty);
|
trait_fty);
|
||||||
|
|
||||||
let (impl_err_span, trait_err_span) =
|
let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(&infcx,
|
||||||
extract_spans_for_error_reporting(&infcx, &terr, origin, impl_m,
|
&terr,
|
||||||
impl_sig, trait_m, trait_sig);
|
origin,
|
||||||
|
impl_m,
|
||||||
|
impl_sig,
|
||||||
|
trait_m,
|
||||||
|
trait_sig);
|
||||||
|
|
||||||
let origin = TypeOrigin::MethodCompatCheck(impl_err_span);
|
let origin = TypeOrigin::MethodCompatCheck(impl_err_span);
|
||||||
|
|
||||||
let mut diag = struct_span_err!(
|
let mut diag = struct_span_err!(tcx.sess,
|
||||||
tcx.sess, origin.span(), E0053,
|
origin.span(),
|
||||||
"method `{}` has an incompatible type for trait", trait_m.name
|
E0053,
|
||||||
);
|
"method `{}` has an incompatible type for trait",
|
||||||
|
trait_m.name);
|
||||||
|
|
||||||
infcx.note_type_err(
|
infcx.note_type_err(&mut diag,
|
||||||
&mut diag,
|
origin,
|
||||||
origin,
|
trait_err_span.map(|sp| (sp, format!("type in trait"))),
|
||||||
trait_err_span.map(|sp| (sp, format!("type in trait"))),
|
Some(infer::ValuePairs::Types(ExpectedFound {
|
||||||
Some(infer::ValuePairs::Types(ExpectedFound {
|
expected: trait_fty,
|
||||||
expected: trait_fty,
|
found: impl_fty,
|
||||||
found: impl_fty
|
})),
|
||||||
})),
|
&terr);
|
||||||
&terr
|
|
||||||
);
|
|
||||||
diag.emit();
|
diag.emit();
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that all obligations are satisfied by the implementation's
|
// Check that all obligations are satisfied by the implementation's
|
||||||
// version.
|
// version.
|
||||||
if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
|
if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
|
||||||
infcx.report_fulfillment_errors(errors);
|
infcx.report_fulfillment_errors(errors);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, resolve all regions. This catches wily misuses of
|
// Finally, resolve all regions. This catches wily misuses of
|
||||||
|
@ -480,8 +482,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
impl_generics: &ty::Generics<'tcx>,
|
impl_generics: &ty::Generics<'tcx>,
|
||||||
trait_to_skol_substs: &Substs<'tcx>,
|
trait_to_skol_substs: &Substs<'tcx>,
|
||||||
impl_to_skol_substs: &Substs<'tcx>)
|
impl_to_skol_substs: &Substs<'tcx>)
|
||||||
-> bool
|
-> bool {
|
||||||
{
|
|
||||||
|
|
||||||
let trait_params = &trait_generics.regions[..];
|
let trait_params = &trait_generics.regions[..];
|
||||||
let impl_params = &impl_generics.regions[..];
|
let impl_params = &impl_generics.regions[..];
|
||||||
|
@ -506,9 +507,12 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
// are zero. Since I don't quite know how to phrase things at
|
// are zero. Since I don't quite know how to phrase things at
|
||||||
// the moment, give a kind of vague error message.
|
// the moment, give a kind of vague error message.
|
||||||
if trait_params.len() != impl_params.len() {
|
if trait_params.len() != impl_params.len() {
|
||||||
struct_span_err!(ccx.tcx.sess, span, E0195,
|
struct_span_err!(ccx.tcx.sess,
|
||||||
"lifetime parameters or bounds on method `{}` do \
|
span,
|
||||||
not match the trait declaration",impl_m.name)
|
E0195,
|
||||||
|
"lifetime parameters or bounds on method `{}` do not match the \
|
||||||
|
trait declaration",
|
||||||
|
impl_m.name)
|
||||||
.span_label(span, &format!("lifetimes do not match trait"))
|
.span_label(span, &format!("lifetimes do not match trait"))
|
||||||
.emit();
|
.emit();
|
||||||
return false;
|
return false;
|
||||||
|
@ -524,40 +528,51 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
impl_sig: ty::FnSig<'tcx>,
|
impl_sig: ty::FnSig<'tcx>,
|
||||||
trait_m: &ty::Method,
|
trait_m: &ty::Method,
|
||||||
trait_sig: ty::FnSig<'tcx>)
|
trait_sig: ty::FnSig<'tcx>)
|
||||||
-> (Span, Option<Span>) {
|
-> (Span, Option<Span>) {
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
|
let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
|
||||||
let (impl_m_output, impl_m_iter) = match tcx.map.expect_impl_item(impl_m_node_id).node {
|
let (impl_m_output, impl_m_iter) = match tcx.map.expect_impl_item(impl_m_node_id).node {
|
||||||
ImplItemKind::Method(ref impl_m_sig, _) =>
|
ImplItemKind::Method(ref impl_m_sig, _) => {
|
||||||
(&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter()),
|
(&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter())
|
||||||
_ => bug!("{:?} is not a method", impl_m)
|
}
|
||||||
|
_ => bug!("{:?} is not a method", impl_m),
|
||||||
};
|
};
|
||||||
|
|
||||||
match *terr {
|
match *terr {
|
||||||
TypeError::Mutability => {
|
TypeError::Mutability => {
|
||||||
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
|
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
|
||||||
let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
|
let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
|
||||||
TraitItem_::MethodTraitItem(ref trait_m_sig, _) =>
|
TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
|
||||||
trait_m_sig.decl.inputs.iter(),
|
trait_m_sig.decl.inputs.iter()
|
||||||
_ => bug!("{:?} is not a MethodTraitItem", trait_m)
|
}
|
||||||
|
_ => bug!("{:?} is not a MethodTraitItem", trait_m),
|
||||||
};
|
};
|
||||||
|
|
||||||
impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| {
|
impl_m_iter.zip(trait_m_iter)
|
||||||
match (&impl_arg.ty.node, &trait_arg.ty.node) {
|
.find(|&(ref impl_arg, ref trait_arg)| {
|
||||||
(&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
|
match (&impl_arg.ty.node, &trait_arg.ty.node) {
|
||||||
(&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) =>
|
(&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
|
||||||
impl_mt.mutbl != trait_mt.mutbl,
|
(&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => {
|
||||||
_ => false
|
impl_mt.mutbl != trait_mt.mutbl
|
||||||
}
|
}
|
||||||
}).map(|(ref impl_arg, ref trait_arg)| {
|
_ => false,
|
||||||
match (impl_arg.to_self(), trait_arg.to_self()) {
|
}
|
||||||
(Some(impl_self), Some(trait_self)) =>
|
})
|
||||||
(impl_self.span, Some(trait_self.span)),
|
.map(|(ref impl_arg, ref trait_arg)| {
|
||||||
(None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
|
match (impl_arg.to_self(), trait_arg.to_self()) {
|
||||||
_ => bug!("impl and trait fns have different first args, \
|
(Some(impl_self), Some(trait_self)) => {
|
||||||
impl: {:?}, trait: {:?}", impl_arg, trait_arg)
|
(impl_self.span, Some(trait_self.span))
|
||||||
}
|
}
|
||||||
}).unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id)))
|
(None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
|
||||||
|
_ => {
|
||||||
|
bug!("impl and trait fns have different first args, impl: \
|
||||||
|
{:?}, trait: {:?}",
|
||||||
|
impl_arg,
|
||||||
|
trait_arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id)))
|
||||||
} else {
|
} else {
|
||||||
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
|
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
|
||||||
}
|
}
|
||||||
|
@ -565,25 +580,28 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
TypeError::Sorts(ExpectedFound { .. }) => {
|
TypeError::Sorts(ExpectedFound { .. }) => {
|
||||||
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
|
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
|
||||||
let (trait_m_output, trait_m_iter) =
|
let (trait_m_output, trait_m_iter) =
|
||||||
match tcx.map.expect_trait_item(trait_m_node_id).node {
|
match tcx.map.expect_trait_item(trait_m_node_id).node {
|
||||||
TraitItem_::MethodTraitItem(ref trait_m_sig, _) =>
|
TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
|
||||||
(&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter()),
|
(&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter())
|
||||||
_ => bug!("{:?} is not a MethodTraitItem", trait_m)
|
}
|
||||||
};
|
_ => bug!("{:?} is not a MethodTraitItem", trait_m),
|
||||||
|
};
|
||||||
|
|
||||||
let impl_iter = impl_sig.inputs.iter();
|
let impl_iter = impl_sig.inputs.iter();
|
||||||
let trait_iter = trait_sig.inputs.iter();
|
let trait_iter = trait_sig.inputs.iter();
|
||||||
impl_iter.zip(trait_iter).zip(impl_m_iter).zip(trait_m_iter)
|
impl_iter.zip(trait_iter)
|
||||||
|
.zip(impl_m_iter)
|
||||||
|
.zip(trait_m_iter)
|
||||||
.filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
|
.filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
|
||||||
match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) {
|
match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) {
|
||||||
Ok(_) => None,
|
Ok(_) => None,
|
||||||
Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span)))
|
Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.next()
|
.next()
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
if infcx.sub_types(false, origin, impl_sig.output,
|
if infcx.sub_types(false, origin, impl_sig.output, trait_sig.output)
|
||||||
trait_sig.output).is_err() {
|
.is_err() {
|
||||||
(impl_m_output.span(), Some(trait_m_output.span()))
|
(impl_m_output.span(), Some(trait_m_output.span()))
|
||||||
} else {
|
} else {
|
||||||
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
|
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
|
||||||
|
@ -593,7 +611,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
|
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (origin.span(), tcx.map.span_if_local(trait_m.def_id))
|
_ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -603,8 +621,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
impl_c_span: Span,
|
impl_c_span: Span,
|
||||||
trait_c: &ty::AssociatedConst<'tcx>,
|
trait_c: &ty::AssociatedConst<'tcx>,
|
||||||
impl_trait_ref: &ty::TraitRef<'tcx>) {
|
impl_trait_ref: &ty::TraitRef<'tcx>) {
|
||||||
debug!("compare_const_impl(impl_trait_ref={:?})",
|
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
|
||||||
impl_trait_ref);
|
|
||||||
|
|
||||||
let tcx = ccx.tcx;
|
let tcx = ccx.tcx;
|
||||||
tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
|
tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
|
||||||
|
@ -626,11 +643,12 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
let impl_to_skol_substs = &impl_param_env.free_substs;
|
let impl_to_skol_substs = &impl_param_env.free_substs;
|
||||||
|
|
||||||
// Create mapping from trait to skolemized.
|
// Create mapping from trait to skolemized.
|
||||||
let trait_to_skol_substs =
|
let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx,
|
||||||
impl_to_skol_substs.rebase_onto(tcx, impl_c.container.id(),
|
impl_c.container.id(),
|
||||||
trait_to_impl_substs.subst(tcx, impl_to_skol_substs));
|
trait_to_impl_substs.subst(tcx,
|
||||||
|
impl_to_skol_substs));
|
||||||
debug!("compare_const_impl: trait_to_skol_substs={:?}",
|
debug!("compare_const_impl: trait_to_skol_substs={:?}",
|
||||||
trait_to_skol_substs);
|
trait_to_skol_substs);
|
||||||
|
|
||||||
// Compute skolemized form of impl and trait const tys.
|
// Compute skolemized form of impl and trait const tys.
|
||||||
let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
|
let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
|
||||||
|
@ -639,31 +657,27 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
|
|
||||||
let err = infcx.commit_if_ok(|_| {
|
let err = infcx.commit_if_ok(|_| {
|
||||||
// There is no "body" here, so just pass dummy id.
|
// There is no "body" here, so just pass dummy id.
|
||||||
let impl_ty =
|
let impl_ty = assoc::normalize_associated_types_in(&infcx,
|
||||||
assoc::normalize_associated_types_in(&infcx,
|
&mut fulfillment_cx,
|
||||||
&mut fulfillment_cx,
|
impl_c_span,
|
||||||
impl_c_span,
|
ast::CRATE_NODE_ID,
|
||||||
ast::CRATE_NODE_ID,
|
&impl_ty);
|
||||||
&impl_ty);
|
|
||||||
|
|
||||||
debug!("compare_const_impl: impl_ty={:?}",
|
debug!("compare_const_impl: impl_ty={:?}", impl_ty);
|
||||||
impl_ty);
|
|
||||||
|
|
||||||
let trait_ty =
|
let trait_ty = assoc::normalize_associated_types_in(&infcx,
|
||||||
assoc::normalize_associated_types_in(&infcx,
|
&mut fulfillment_cx,
|
||||||
&mut fulfillment_cx,
|
impl_c_span,
|
||||||
impl_c_span,
|
ast::CRATE_NODE_ID,
|
||||||
ast::CRATE_NODE_ID,
|
&trait_ty);
|
||||||
&trait_ty);
|
|
||||||
|
|
||||||
debug!("compare_const_impl: trait_ty={:?}",
|
debug!("compare_const_impl: trait_ty={:?}", 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, .. }| {
|
.map(|InferOk { obligations, .. }| {
|
||||||
// FIXME(#32730) propagate obligations
|
// FIXME(#32730) propagate obligations
|
||||||
assert!(obligations.is_empty())
|
assert!(obligations.is_empty())
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Err(terr) = err {
|
if let Err(terr) = err {
|
||||||
|
@ -674,31 +688,31 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
// Locate the Span containing just the type of the offending impl
|
// Locate the Span containing just the type of the offending impl
|
||||||
match tcx.map.expect_impl_item(impl_c_node_id).node {
|
match tcx.map.expect_impl_item(impl_c_node_id).node {
|
||||||
ImplItemKind::Const(ref ty, _) => origin = TypeOrigin::Misc(ty.span),
|
ImplItemKind::Const(ref ty, _) => origin = TypeOrigin::Misc(ty.span),
|
||||||
_ => bug!("{:?} is not a impl const", impl_c)
|
_ => bug!("{:?} is not a impl const", impl_c),
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diag = struct_span_err!(
|
let mut diag = struct_span_err!(tcx.sess,
|
||||||
tcx.sess, origin.span(), E0326,
|
origin.span(),
|
||||||
"implemented const `{}` has an incompatible type for trait",
|
E0326,
|
||||||
trait_c.name
|
"implemented const `{}` has an incompatible type for \
|
||||||
);
|
trait",
|
||||||
|
trait_c.name);
|
||||||
|
|
||||||
// Add a label to the Span containing just the type of the item
|
// Add a label to the Span containing just the type of the item
|
||||||
let trait_c_node_id = tcx.map.as_local_node_id(trait_c.def_id).unwrap();
|
let trait_c_node_id = tcx.map.as_local_node_id(trait_c.def_id).unwrap();
|
||||||
let trait_c_span = match tcx.map.expect_trait_item(trait_c_node_id).node {
|
let trait_c_span = match tcx.map.expect_trait_item(trait_c_node_id).node {
|
||||||
TraitItem_::ConstTraitItem(ref ty, _) => ty.span,
|
TraitItem_::ConstTraitItem(ref ty, _) => ty.span,
|
||||||
_ => bug!("{:?} is not a trait const", trait_c)
|
_ => bug!("{:?} is not a trait const", trait_c),
|
||||||
};
|
};
|
||||||
|
|
||||||
infcx.note_type_err(
|
infcx.note_type_err(&mut diag,
|
||||||
&mut diag,
|
origin,
|
||||||
origin,
|
Some((trait_c_span, format!("type in trait"))),
|
||||||
Some((trait_c_span, format!("type in trait"))),
|
Some(infer::ValuePairs::Types(ExpectedFound {
|
||||||
Some(infer::ValuePairs::Types(ExpectedFound {
|
expected: trait_ty,
|
||||||
expected: trait_ty,
|
found: impl_ty,
|
||||||
found: impl_ty
|
})),
|
||||||
})), &terr
|
&terr);
|
||||||
);
|
|
||||||
diag.emit();
|
diag.emit();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue