mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-12 16:45:37 +00:00
Auto merge of #42281 - eddyb:well-adjusted, r=nikomatsakis
Decompose Adjustment into smaller steps and remove the method map. The method map held method callee information for: * actual method calls (`x.f(...)`) * overloaded unary, binary, indexing and call operators * *every overloaded deref adjustment* (many can exist for each expression) That last one was a historical ~~accident~~ hack, and part of the motivation for this PR, along with: * a desire to compose adjustments more freely * containing the autoderef logic better to avoid mutation within an inference snapshot * not creating `TyFnDef` types which are incompatible with the original one * i.e. we used to take a`TyFnDef`'s `for<'a> &'a T -> &'a U` signature and instantiate `'a` using a region inference variable, *then* package the resulting `&'b T -> &'b U` signature in another `TyFnDef`, while keeping *the same* `DefId` and `Substs` * to fix #3548 by explicitly writing autorefs for the RHS of comparison operators Individual commits tell their own story, of "atomic" changes avoiding breaking semantics. Future work based on this PR could include: * removing the signature from `TyFnDef`, now that it's always "canonical" * some questions of variance remain, as subtyping *still* treats the signature differently * moving part of the typeck logic for methods, autoderef and coercion into `rustc::traits` * allowing LUB coercions (joining multiple expressions) to "stack up" many adjustments * transitive coercions (e.g. reify or unsize after multiple steps of autoderef) r? @nikomatsakis
This commit is contained in:
commit
4ed2edaafe
@ -134,22 +134,22 @@ fn test_push() {
|
||||
fn test_push_unique() {
|
||||
let mut heap = BinaryHeap::<Box<_>>::from(vec![box 2, box 4, box 9]);
|
||||
assert_eq!(heap.len(), 3);
|
||||
assert!(*heap.peek().unwrap() == box 9);
|
||||
assert!(**heap.peek().unwrap() == 9);
|
||||
heap.push(box 11);
|
||||
assert_eq!(heap.len(), 4);
|
||||
assert!(*heap.peek().unwrap() == box 11);
|
||||
assert!(**heap.peek().unwrap() == 11);
|
||||
heap.push(box 5);
|
||||
assert_eq!(heap.len(), 5);
|
||||
assert!(*heap.peek().unwrap() == box 11);
|
||||
assert!(**heap.peek().unwrap() == 11);
|
||||
heap.push(box 27);
|
||||
assert_eq!(heap.len(), 6);
|
||||
assert!(*heap.peek().unwrap() == box 27);
|
||||
assert!(**heap.peek().unwrap() == 27);
|
||||
heap.push(box 3);
|
||||
assert_eq!(heap.len(), 7);
|
||||
assert!(*heap.peek().unwrap() == box 27);
|
||||
assert!(**heap.peek().unwrap() == 27);
|
||||
heap.push(box 103);
|
||||
assert_eq!(heap.len(), 8);
|
||||
assert!(*heap.peek().unwrap() == box 103);
|
||||
assert!(**heap.peek().unwrap() == 103);
|
||||
}
|
||||
|
||||
fn check_to_vec(mut data: Vec<i32>) {
|
||||
|
@ -355,11 +355,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
||||
}
|
||||
|
||||
hir::ExprIndex(ref l, ref r) |
|
||||
hir::ExprBinary(_, ref l, ref r) if self.tables.is_method_call(expr.id) => {
|
||||
hir::ExprBinary(_, ref l, ref r) if self.tables.is_method_call(expr) => {
|
||||
self.call(expr, pred, &l, Some(&**r).into_iter())
|
||||
}
|
||||
|
||||
hir::ExprUnary(_, ref e) if self.tables.is_method_call(expr.id) => {
|
||||
hir::ExprUnary(_, ref e) if self.tables.is_method_call(expr) => {
|
||||
self.call(expr, pred, &e, None::<hir::Expr>.iter())
|
||||
}
|
||||
|
||||
@ -412,16 +412,10 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
||||
pred: CFGIndex,
|
||||
func_or_rcvr: &hir::Expr,
|
||||
args: I) -> CFGIndex {
|
||||
let method_call = ty::MethodCall::expr(call_expr.id);
|
||||
let fn_ty = match self.tables.method_map.get(&method_call) {
|
||||
Some(method) => method.ty,
|
||||
None => self.tables.expr_ty_adjusted(func_or_rcvr),
|
||||
};
|
||||
|
||||
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
|
||||
let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
|
||||
// FIXME(canndrew): This is_never should probably be an is_uninhabited.
|
||||
if fn_ty.fn_ret().0.is_never() {
|
||||
if self.tables.expr_ty(call_expr).is_never() {
|
||||
self.add_unreachable_node()
|
||||
} else {
|
||||
ret
|
||||
|
@ -19,8 +19,6 @@ use std::mem;
|
||||
use syntax_pos::symbol::InternedString;
|
||||
use ty;
|
||||
|
||||
impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs });
|
||||
|
||||
impl<'a, 'tcx, T> HashStable<StableHashingContext<'a, 'tcx>> for &'tcx ty::Slice<T>
|
||||
where T: HashStable<StableHashingContext<'a, 'tcx>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
@ -101,19 +99,20 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::adjustment::Ad
|
||||
ty::adjustment::Adjust::ReifyFnPointer |
|
||||
ty::adjustment::Adjust::UnsafeFnPointer |
|
||||
ty::adjustment::Adjust::ClosureFnPointer |
|
||||
ty::adjustment::Adjust::MutToConstPointer => {}
|
||||
ty::adjustment::Adjust::DerefRef { autoderefs, ref autoref, unsize } => {
|
||||
autoderefs.hash_stable(hcx, hasher);
|
||||
ty::adjustment::Adjust::MutToConstPointer |
|
||||
ty::adjustment::Adjust::Unsize => {}
|
||||
ty::adjustment::Adjust::Deref(ref overloaded) => {
|
||||
overloaded.hash_stable(hcx, hasher);
|
||||
}
|
||||
ty::adjustment::Adjust::Borrow(ref autoref) => {
|
||||
autoref.hash_stable(hcx, hasher);
|
||||
unsize.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target });
|
||||
impl_stable_hash_for!(struct ty::MethodCall { expr_id, autoderef });
|
||||
impl_stable_hash_for!(struct ty::MethodCallee<'tcx> { def_id, ty, substs });
|
||||
impl_stable_hash_for!(struct ty::adjustment::OverloadedDeref<'tcx> { region, mutbl });
|
||||
impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id });
|
||||
impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region });
|
||||
|
||||
@ -601,11 +600,10 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::TypeckTables<'
|
||||
hcx: &mut StableHashingContext<'a, 'tcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let ty::TypeckTables {
|
||||
ref type_relative_path_defs,
|
||||
ref type_dependent_defs,
|
||||
ref node_types,
|
||||
ref item_substs,
|
||||
ref node_substs,
|
||||
ref adjustments,
|
||||
ref method_map,
|
||||
ref upvar_capture_map,
|
||||
ref closure_tys,
|
||||
ref closure_kinds,
|
||||
@ -622,21 +620,10 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::TypeckTables<'
|
||||
} = *self;
|
||||
|
||||
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
|
||||
ich::hash_stable_nodemap(hcx, hasher, type_relative_path_defs);
|
||||
ich::hash_stable_nodemap(hcx, hasher, type_dependent_defs);
|
||||
ich::hash_stable_nodemap(hcx, hasher, node_types);
|
||||
ich::hash_stable_nodemap(hcx, hasher, item_substs);
|
||||
ich::hash_stable_nodemap(hcx, hasher, node_substs);
|
||||
ich::hash_stable_nodemap(hcx, hasher, adjustments);
|
||||
|
||||
ich::hash_stable_hashmap(hcx, hasher, method_map, |hcx, method_call| {
|
||||
let ty::MethodCall {
|
||||
expr_id,
|
||||
autoderef
|
||||
} = *method_call;
|
||||
|
||||
let def_id = hcx.tcx().hir.local_def_id(expr_id);
|
||||
(hcx.def_path_hash(def_id), autoderef)
|
||||
});
|
||||
|
||||
ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| {
|
||||
let ty::UpvarId {
|
||||
var_id,
|
||||
|
@ -564,13 +564,14 @@ impl<'tcx, T> InferOk<'tcx, T> {
|
||||
}
|
||||
|
||||
#[must_use = "once you start a snapshot, you should always consume it"]
|
||||
pub struct CombinedSnapshot {
|
||||
pub struct CombinedSnapshot<'a, 'tcx:'a> {
|
||||
projection_cache_snapshot: traits::ProjectionCacheSnapshot,
|
||||
type_snapshot: type_variable::Snapshot,
|
||||
int_snapshot: unify::Snapshot<ty::IntVid>,
|
||||
float_snapshot: unify::Snapshot<ty::FloatVid>,
|
||||
region_vars_snapshot: RegionSnapshot,
|
||||
was_in_snapshot: bool,
|
||||
_in_progress_tables: Option<Ref<'a, ty::TypeckTables<'tcx>>>,
|
||||
}
|
||||
|
||||
/// Helper trait for shortening the lifetimes inside a
|
||||
@ -888,7 +889,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
result
|
||||
}
|
||||
|
||||
fn start_snapshot(&self) -> CombinedSnapshot {
|
||||
fn start_snapshot<'b>(&'b self) -> CombinedSnapshot<'b, 'tcx> {
|
||||
debug!("start_snapshot()");
|
||||
|
||||
let in_snapshot = self.in_snapshot.get();
|
||||
@ -901,6 +902,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
float_snapshot: self.float_unification_table.borrow_mut().snapshot(),
|
||||
region_vars_snapshot: self.region_vars.start_snapshot(),
|
||||
was_in_snapshot: in_snapshot,
|
||||
// Borrow tables "in progress" (i.e. during typeck)
|
||||
// to ban writes from within a snapshot to them.
|
||||
_in_progress_tables: match self.tables {
|
||||
InferTables::InProgress(ref tables) => tables.try_borrow().ok(),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -911,7 +918,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
int_snapshot,
|
||||
float_snapshot,
|
||||
region_vars_snapshot,
|
||||
was_in_snapshot } = snapshot;
|
||||
was_in_snapshot,
|
||||
_in_progress_tables } = snapshot;
|
||||
|
||||
self.in_snapshot.set(was_in_snapshot);
|
||||
|
||||
@ -938,7 +946,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
int_snapshot,
|
||||
float_snapshot,
|
||||
region_vars_snapshot,
|
||||
was_in_snapshot } = snapshot;
|
||||
was_in_snapshot,
|
||||
_in_progress_tables } = snapshot;
|
||||
|
||||
self.in_snapshot.set(was_in_snapshot);
|
||||
|
||||
@ -1645,29 +1654,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
!traits::type_known_to_meet_bound(self, ty, copy_def_id, span)
|
||||
}
|
||||
|
||||
pub fn node_method_ty(&self, method_call: ty::MethodCall)
|
||||
-> Option<Ty<'tcx>> {
|
||||
self.tables
|
||||
.borrow()
|
||||
.method_map
|
||||
.get(&method_call)
|
||||
.map(|method| method.ty)
|
||||
.map(|ty| self.resolve_type_vars_if_possible(&ty))
|
||||
}
|
||||
|
||||
pub fn node_method_id(&self, method_call: ty::MethodCall)
|
||||
-> Option<DefId> {
|
||||
self.tables
|
||||
.borrow()
|
||||
.method_map
|
||||
.get(&method_call)
|
||||
.map(|method| method.def_id)
|
||||
}
|
||||
|
||||
pub fn is_method_call(&self, id: ast::NodeId) -> bool {
|
||||
self.tables.borrow().method_map.contains_key(&ty::MethodCall::expr(id))
|
||||
}
|
||||
|
||||
pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
|
||||
self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned()
|
||||
}
|
||||
|
@ -95,9 +95,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn lookup_and_handle_method(&mut self, id: ast::NodeId) {
|
||||
let method_call = ty::MethodCall::expr(id);
|
||||
let method = self.tables.method_map[&method_call];
|
||||
self.check_def_id(method.def_id);
|
||||
self.check_def_id(self.tables.type_dependent_defs[&id].def_id());
|
||||
}
|
||||
|
||||
fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) {
|
||||
|
@ -13,7 +13,6 @@
|
||||
use self::RootUnsafeContext::*;
|
||||
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::MethodCall;
|
||||
use lint;
|
||||
|
||||
use syntax::ast;
|
||||
@ -174,8 +173,8 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
|
||||
match expr.node {
|
||||
hir::ExprMethodCall(..) => {
|
||||
let method_call = MethodCall::expr(expr.id);
|
||||
let base_type = self.tables.method_map[&method_call].ty;
|
||||
let def_id = self.tables.type_dependent_defs[&expr.id].def_id();
|
||||
let base_type = self.tcx.type_of(def_id);
|
||||
debug!("effect: method call case, base type is {:?}",
|
||||
base_type);
|
||||
if type_is_unsafe_function(base_type) {
|
||||
|
@ -263,12 +263,6 @@ macro_rules! return_if_err {
|
||||
)
|
||||
}
|
||||
|
||||
/// Whether the elements of an overloaded operation are passed by value or by reference
|
||||
enum PassArgs {
|
||||
ByValue,
|
||||
ByRef,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||
pub fn new(delegate: &'a mut (Delegate<'tcx>+'a),
|
||||
region_maps: &'a RegionMaps,
|
||||
@ -382,9 +376,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
hir::ExprUnary(hir::UnDeref, ref base) => { // *base
|
||||
if !self.walk_overloaded_operator(expr, &base, Vec::new(), PassArgs::ByRef) {
|
||||
self.select_from_expr(&base);
|
||||
}
|
||||
self.select_from_expr(&base);
|
||||
}
|
||||
|
||||
hir::ExprField(ref base, _) => { // base.f
|
||||
@ -396,13 +388,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
hir::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs]
|
||||
if !self.walk_overloaded_operator(expr,
|
||||
&lhs,
|
||||
vec![&rhs],
|
||||
PassArgs::ByValue) {
|
||||
self.select_from_expr(&lhs);
|
||||
self.consume_expr(&rhs);
|
||||
}
|
||||
self.select_from_expr(&lhs);
|
||||
self.consume_expr(&rhs);
|
||||
}
|
||||
|
||||
hir::ExprCall(ref callee, ref args) => { // callee(args)
|
||||
@ -485,29 +472,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||
self.walk_block(&blk);
|
||||
}
|
||||
|
||||
hir::ExprUnary(op, ref lhs) => {
|
||||
let pass_args = if op.is_by_value() {
|
||||
PassArgs::ByValue
|
||||
} else {
|
||||
PassArgs::ByRef
|
||||
};
|
||||
|
||||
if !self.walk_overloaded_operator(expr, &lhs, Vec::new(), pass_args) {
|
||||
self.consume_expr(&lhs);
|
||||
}
|
||||
hir::ExprUnary(_, ref lhs) => {
|
||||
self.consume_expr(&lhs);
|
||||
}
|
||||
|
||||
hir::ExprBinary(op, ref lhs, ref rhs) => {
|
||||
let pass_args = if op.node.is_by_value() {
|
||||
PassArgs::ByValue
|
||||
} else {
|
||||
PassArgs::ByRef
|
||||
};
|
||||
|
||||
if !self.walk_overloaded_operator(expr, &lhs, vec![&rhs], pass_args) {
|
||||
self.consume_expr(&lhs);
|
||||
self.consume_expr(&rhs);
|
||||
}
|
||||
hir::ExprBinary(_, ref lhs, ref rhs) => {
|
||||
self.consume_expr(&lhs);
|
||||
self.consume_expr(&rhs);
|
||||
}
|
||||
|
||||
hir::ExprBlock(ref blk) => {
|
||||
@ -529,14 +500,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||
self.consume_expr(&base);
|
||||
}
|
||||
|
||||
hir::ExprAssignOp(op, ref lhs, ref rhs) => {
|
||||
// NB All our assignment operations take the RHS by value
|
||||
assert!(op.node.is_by_value());
|
||||
|
||||
if !self.walk_overloaded_operator(expr, lhs, vec![rhs], PassArgs::ByValue) {
|
||||
hir::ExprAssignOp(_, ref lhs, ref rhs) => {
|
||||
if self.mc.infcx.tables.borrow().is_method_call(expr) {
|
||||
self.consume_expr(lhs);
|
||||
} else {
|
||||
self.mutate_expr(expr, &lhs, MutateMode::WriteAndRead);
|
||||
self.consume_expr(&rhs);
|
||||
}
|
||||
self.consume_expr(&rhs);
|
||||
}
|
||||
|
||||
hir::ExprRepeat(ref base, _) => {
|
||||
@ -563,19 +533,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
ty::TyError => { }
|
||||
_ => {
|
||||
let overloaded_call_type =
|
||||
match self.mc.infcx.node_method_id(ty::MethodCall::expr(call.id)) {
|
||||
Some(method_id) => {
|
||||
OverloadedCallType::from_method_id(self.tcx(), method_id)
|
||||
}
|
||||
None => {
|
||||
span_bug!(
|
||||
callee.span,
|
||||
"unexpected callee type {}",
|
||||
callee_ty)
|
||||
}
|
||||
};
|
||||
match overloaded_call_type {
|
||||
let def_id = self.mc.infcx.tables.borrow().type_dependent_defs[&call.id].def_id();
|
||||
match OverloadedCallType::from_method_id(self.tcx(), def_id) {
|
||||
FnMutOverloadedCall => {
|
||||
let call_scope_r = self.tcx().node_scope_region(call.id);
|
||||
self.borrow_expr(callee,
|
||||
@ -715,102 +674,55 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||
// consumed or borrowed as part of the automatic adjustment
|
||||
// process.
|
||||
fn walk_adjustment(&mut self, expr: &hir::Expr) {
|
||||
let infcx = self.mc.infcx;
|
||||
//NOTE(@jroesch): mixed RefCell borrow causes crash
|
||||
let adj = infcx.tables.borrow().adjustments.get(&expr.id).map(|x| x.clone());
|
||||
if let Some(adjustment) = adj {
|
||||
let adjustments = self.mc.infcx.tables.borrow().expr_adjustments(expr).to_vec();
|
||||
let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
||||
for adjustment in adjustments {
|
||||
debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
|
||||
match adjustment.kind {
|
||||
adjustment::Adjust::NeverToAny |
|
||||
adjustment::Adjust::ReifyFnPointer |
|
||||
adjustment::Adjust::UnsafeFnPointer |
|
||||
adjustment::Adjust::ClosureFnPointer |
|
||||
adjustment::Adjust::MutToConstPointer => {
|
||||
adjustment::Adjust::MutToConstPointer |
|
||||
adjustment::Adjust::Unsize => {
|
||||
// Creating a closure/fn-pointer or unsizing consumes
|
||||
// the input and stores it into the resulting rvalue.
|
||||
debug!("walk_adjustment: trivial adjustment");
|
||||
let cmt_unadjusted =
|
||||
return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
||||
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
|
||||
self.delegate_consume(expr.id, expr.span, cmt.clone());
|
||||
}
|
||||
adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => {
|
||||
debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
|
||||
|
||||
self.walk_autoderefs(expr, autoderefs);
|
||||
adjustment::Adjust::Deref(None) => {}
|
||||
|
||||
let cmt_derefd =
|
||||
return_if_err!(self.mc.cat_expr_autoderefd(expr, autoderefs));
|
||||
// Autoderefs for overloaded Deref calls in fact reference
|
||||
// their receiver. That is, if we have `(*x)` where `x`
|
||||
// is of type `Rc<T>`, then this in fact is equivalent to
|
||||
// `x.deref()`. Since `deref()` is declared with `&self`,
|
||||
// this is an autoref of `x`.
|
||||
adjustment::Adjust::Deref(Some(ref deref)) => {
|
||||
let bk = ty::BorrowKind::from_mutbl(deref.mutbl);
|
||||
self.delegate.borrow(expr.id, expr.span, cmt.clone(),
|
||||
deref.region, bk, AutoRef);
|
||||
}
|
||||
|
||||
let cmt_refd =
|
||||
self.walk_autoref(expr, cmt_derefd, autoref);
|
||||
|
||||
if unsize {
|
||||
// Unsizing consumes the thin pointer and produces a fat one.
|
||||
self.delegate_consume(expr.id, expr.span, cmt_refd);
|
||||
}
|
||||
adjustment::Adjust::Borrow(ref autoref) => {
|
||||
self.walk_autoref(expr, cmt.clone(), autoref);
|
||||
}
|
||||
}
|
||||
cmt = return_if_err!(self.mc.cat_expr_adjusted(expr, cmt, &adjustment));
|
||||
}
|
||||
}
|
||||
|
||||
/// Autoderefs for overloaded Deref calls in fact reference their receiver. That is, if we have
|
||||
/// `(*x)` where `x` is of type `Rc<T>`, then this in fact is equivalent to `x.deref()`. Since
|
||||
/// `deref()` is declared with `&self`, this is an autoref of `x`.
|
||||
fn walk_autoderefs(&mut self,
|
||||
expr: &hir::Expr,
|
||||
autoderefs: usize) {
|
||||
debug!("walk_autoderefs expr={:?} autoderefs={}", expr, autoderefs);
|
||||
|
||||
for i in 0..autoderefs {
|
||||
let deref_id = ty::MethodCall::autoderef(expr.id, i as u32);
|
||||
if let Some(method_ty) = self.mc.infcx.node_method_ty(deref_id) {
|
||||
let cmt = return_if_err!(self.mc.cat_expr_autoderefd(expr, i));
|
||||
|
||||
// the method call infrastructure should have
|
||||
// replaced all late-bound regions with variables:
|
||||
let self_ty = method_ty.fn_sig().input(0);
|
||||
let self_ty = self.tcx().no_late_bound_regions(&self_ty).unwrap();
|
||||
|
||||
let (m, r) = match self_ty.sty {
|
||||
ty::TyRef(r, ref m) => (m.mutbl, r),
|
||||
_ => span_bug!(expr.span,
|
||||
"bad overloaded deref type {:?}",
|
||||
method_ty)
|
||||
};
|
||||
let bk = ty::BorrowKind::from_mutbl(m);
|
||||
self.delegate.borrow(expr.id, expr.span, cmt,
|
||||
r, bk, AutoRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Walks the autoref `opt_autoref` applied to the autoderef'd
|
||||
/// `expr`. `cmt_derefd` is the mem-categorized form of `expr`
|
||||
/// after all relevant autoderefs have occurred. Because AutoRefs
|
||||
/// can be recursive, this function is recursive: it first walks
|
||||
/// deeply all the way down the autoref chain, and then processes
|
||||
/// the autorefs on the way out. At each point, it returns the
|
||||
/// `cmt` for the rvalue that will be produced by introduced an
|
||||
/// autoref.
|
||||
/// Walks the autoref `autoref` applied to the autoderef'd
|
||||
/// `expr`. `cmt_base` is the mem-categorized form of `expr`
|
||||
/// after all relevant autoderefs have occurred.
|
||||
fn walk_autoref(&mut self,
|
||||
expr: &hir::Expr,
|
||||
cmt_base: mc::cmt<'tcx>,
|
||||
opt_autoref: Option<adjustment::AutoBorrow<'tcx>>)
|
||||
-> mc::cmt<'tcx>
|
||||
{
|
||||
debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})",
|
||||
autoref: &adjustment::AutoBorrow<'tcx>) {
|
||||
debug!("walk_autoref(expr.id={} cmt_base={:?} autoref={:?})",
|
||||
expr.id,
|
||||
cmt_base,
|
||||
opt_autoref);
|
||||
|
||||
let cmt_base_ty = cmt_base.ty;
|
||||
|
||||
let autoref = match opt_autoref {
|
||||
Some(ref autoref) => autoref,
|
||||
None => {
|
||||
// No AutoRef.
|
||||
return cmt_base;
|
||||
}
|
||||
};
|
||||
autoref);
|
||||
|
||||
match *autoref {
|
||||
adjustment::AutoBorrow::Ref(r, m) => {
|
||||
@ -840,58 +752,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||
AutoUnsafe);
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the categorization for the result of the autoref.
|
||||
// This is always an rvalue, since we are producing a new
|
||||
// (temporary) indirection.
|
||||
|
||||
let adj_ty = cmt_base_ty.adjust_for_autoref(self.tcx(), opt_autoref);
|
||||
|
||||
self.mc.cat_rvalue_node(expr.id, expr.span, adj_ty)
|
||||
}
|
||||
|
||||
|
||||
// When this returns true, it means that the expression *is* a
|
||||
// method-call (i.e. via the operator-overload). This true result
|
||||
// also implies that walk_overloaded_operator already took care of
|
||||
// recursively processing the input arguments, and thus the caller
|
||||
// should not do so.
|
||||
fn walk_overloaded_operator(&mut self,
|
||||
expr: &hir::Expr,
|
||||
receiver: &hir::Expr,
|
||||
rhs: Vec<&hir::Expr>,
|
||||
pass_args: PassArgs)
|
||||
-> bool
|
||||
{
|
||||
if !self.mc.infcx.is_method_call(expr.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
match pass_args {
|
||||
PassArgs::ByValue => {
|
||||
self.consume_expr(receiver);
|
||||
for &arg in &rhs {
|
||||
self.consume_expr(arg);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
PassArgs::ByRef => {},
|
||||
}
|
||||
|
||||
self.walk_expr(receiver);
|
||||
|
||||
// Arguments (but not receivers) to overloaded operator
|
||||
// methods are implicitly autoref'd which sadly does not use
|
||||
// adjustments, so we must hardcode the borrow here.
|
||||
|
||||
let r = self.tcx().node_scope_region(expr.id);
|
||||
let bk = ty::ImmBorrow;
|
||||
|
||||
for &arg in &rhs {
|
||||
self.borrow_expr(arg, r, bk, OverloadedOperator);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm) -> TrackMatchMode {
|
||||
|
@ -1045,7 +1045,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
|
||||
hir::ExprAssignOp(_, ref l, ref r) => {
|
||||
// an overloaded assign op is like a method call
|
||||
if self.tables.is_method_call(expr.id) {
|
||||
if self.tables.is_method_call(expr) {
|
||||
let succ = self.propagate_through_expr(&l, succ);
|
||||
self.propagate_through_expr(&r, succ)
|
||||
} else {
|
||||
@ -1072,9 +1072,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
|
||||
hir::ExprCall(ref f, ref args) => {
|
||||
// FIXME(canndrew): This is_never should really be an is_uninhabited
|
||||
let diverges = !self.tables.is_method_call(expr.id) &&
|
||||
self.tables.expr_ty_adjusted(&f).fn_ret().0.is_never();
|
||||
let succ = if diverges {
|
||||
let succ = if self.tables.expr_ty(expr).is_never() {
|
||||
self.s.exit_ln
|
||||
} else {
|
||||
succ
|
||||
@ -1084,10 +1082,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
}
|
||||
|
||||
hir::ExprMethodCall(.., ref args) => {
|
||||
let method_call = ty::MethodCall::expr(expr.id);
|
||||
let method_ty = self.tables.method_map[&method_call].ty;
|
||||
// FIXME(canndrew): This is_never should really be an is_uninhabited
|
||||
let succ = if method_ty.fn_ret().0.is_never() {
|
||||
let succ = if self.tables.expr_ty(expr).is_never() {
|
||||
self.s.exit_ln
|
||||
} else {
|
||||
succ
|
||||
@ -1370,7 +1366,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
|
||||
}
|
||||
|
||||
hir::ExprAssignOp(_, ref l, _) => {
|
||||
if !this.tables.is_method_call(expr.id) {
|
||||
if !this.tables.is_method_call(expr) {
|
||||
this.check_lvalue(&l);
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,6 @@
|
||||
pub use self::PointerKind::*;
|
||||
pub use self::InteriorKind::*;
|
||||
pub use self::FieldName::*;
|
||||
pub use self::ElementKind::*;
|
||||
pub use self::MutabilityCategory::*;
|
||||
pub use self::AliasableReason::*;
|
||||
pub use self::Note::*;
|
||||
@ -94,7 +93,7 @@ pub enum Categorization<'tcx> {
|
||||
StaticItem,
|
||||
Upvar(Upvar), // upvar referenced by closure env
|
||||
Local(ast::NodeId), // local variable
|
||||
Deref(cmt<'tcx>, usize, PointerKind<'tcx>), // deref of a ptr
|
||||
Deref(cmt<'tcx>, PointerKind<'tcx>), // deref of a ptr
|
||||
Interior(cmt<'tcx>, InteriorKind), // something interior: field, tuple, etc
|
||||
Downcast(cmt<'tcx>, DefId), // selects a particular enum variant (*1)
|
||||
|
||||
@ -129,7 +128,7 @@ pub enum PointerKind<'tcx> {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum InteriorKind {
|
||||
InteriorField(FieldName),
|
||||
InteriorElement(InteriorOffsetKind, ElementKind),
|
||||
InteriorElement(InteriorOffsetKind),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
@ -144,12 +143,6 @@ pub enum InteriorOffsetKind {
|
||||
Pattern, // e.g. `fn foo([_, a, _, _]: [A; 4]) { ... }`
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum ElementKind {
|
||||
VecElement,
|
||||
OtherElement,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum MutabilityCategory {
|
||||
McImmutable, // Immutable.
|
||||
@ -229,8 +222,8 @@ impl<'tcx> cmt_<'tcx> {
|
||||
|
||||
pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
|
||||
match self.cat {
|
||||
Categorization::Deref(ref base_cmt, _, BorrowedPtr(ty::ImmBorrow, _)) |
|
||||
Categorization::Deref(ref base_cmt, _, Implicit(ty::ImmBorrow, _)) => {
|
||||
Categorization::Deref(ref base_cmt, BorrowedPtr(ty::ImmBorrow, _)) |
|
||||
Categorization::Deref(ref base_cmt, Implicit(ty::ImmBorrow, _)) => {
|
||||
// try to figure out where the immutable reference came from
|
||||
match base_cmt.cat {
|
||||
Categorization::Local(node_id) =>
|
||||
@ -255,13 +248,13 @@ impl<'tcx> cmt_<'tcx> {
|
||||
}
|
||||
Categorization::Rvalue(..) |
|
||||
Categorization::Upvar(..) |
|
||||
Categorization::Deref(.., UnsafePtr(..)) => {
|
||||
Categorization::Deref(_, UnsafePtr(..)) => {
|
||||
// This should not be reachable up to inference limitations.
|
||||
None
|
||||
}
|
||||
Categorization::Interior(ref base_cmt, _) |
|
||||
Categorization::Downcast(ref base_cmt, _) |
|
||||
Categorization::Deref(ref base_cmt, _, _) => {
|
||||
Categorization::Deref(ref base_cmt, _) => {
|
||||
base_cmt.immutability_blame()
|
||||
}
|
||||
Categorization::StaticItem => {
|
||||
@ -473,53 +466,64 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
pub fn cat_expr(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
|
||||
match self.infcx.tables.borrow().adjustments.get(&expr.id) {
|
||||
None => {
|
||||
// No adjustments.
|
||||
self.cat_expr_unadjusted(expr)
|
||||
}
|
||||
|
||||
Some(adjustment) => {
|
||||
match adjustment.kind {
|
||||
adjustment::Adjust::DerefRef {
|
||||
autoderefs,
|
||||
autoref: None,
|
||||
unsize: false
|
||||
} => {
|
||||
// Equivalent to *expr or something similar.
|
||||
self.cat_expr_autoderefd(expr, autoderefs)
|
||||
}
|
||||
|
||||
adjustment::Adjust::NeverToAny |
|
||||
adjustment::Adjust::ReifyFnPointer |
|
||||
adjustment::Adjust::UnsafeFnPointer |
|
||||
adjustment::Adjust::ClosureFnPointer |
|
||||
adjustment::Adjust::MutToConstPointer |
|
||||
adjustment::Adjust::DerefRef {..} => {
|
||||
debug!("cat_expr({:?}): {:?}",
|
||||
adjustment,
|
||||
expr);
|
||||
// Result is an rvalue.
|
||||
let expr_ty = self.expr_ty_adjusted(expr)?;
|
||||
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
|
||||
}
|
||||
// This recursion helper avoids going through *too many*
|
||||
// adjustments, since *only* non-overloaded deref recurses.
|
||||
fn helper<'a, 'gcx, 'tcx>(mc: &MemCategorizationContext<'a, 'gcx, 'tcx>,
|
||||
expr: &hir::Expr,
|
||||
adjustments: &[adjustment::Adjustment<'tcx>])
|
||||
-> McResult<cmt<'tcx>> {
|
||||
match adjustments.split_last() {
|
||||
None => mc.cat_expr_unadjusted(expr),
|
||||
Some((adjustment, previous)) => {
|
||||
mc.cat_expr_adjusted_with(expr, || helper(mc, expr, previous), adjustment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
helper(self, expr, self.infcx.tables.borrow().expr_adjustments(expr))
|
||||
}
|
||||
|
||||
pub fn cat_expr_autoderefd(&self,
|
||||
expr: &hir::Expr,
|
||||
autoderefs: usize)
|
||||
-> McResult<cmt<'tcx>> {
|
||||
let mut cmt = self.cat_expr_unadjusted(expr)?;
|
||||
debug!("cat_expr_autoderefd: autoderefs={}, cmt={:?}",
|
||||
autoderefs,
|
||||
cmt);
|
||||
for deref in 1..autoderefs + 1 {
|
||||
cmt = self.cat_deref(expr, cmt, deref)?;
|
||||
pub fn cat_expr_adjusted(&self, expr: &hir::Expr,
|
||||
previous: cmt<'tcx>,
|
||||
adjustment: &adjustment::Adjustment<'tcx>)
|
||||
-> McResult<cmt<'tcx>> {
|
||||
self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
|
||||
}
|
||||
|
||||
fn cat_expr_adjusted_with<F>(&self, expr: &hir::Expr,
|
||||
previous: F,
|
||||
adjustment: &adjustment::Adjustment<'tcx>)
|
||||
-> McResult<cmt<'tcx>>
|
||||
where F: FnOnce() -> McResult<cmt<'tcx>>
|
||||
{
|
||||
debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr);
|
||||
let target = self.infcx.resolve_type_vars_if_possible(&adjustment.target);
|
||||
match adjustment.kind {
|
||||
adjustment::Adjust::Deref(overloaded) => {
|
||||
// Equivalent to *expr or something similar.
|
||||
let base = if let Some(deref) = overloaded {
|
||||
let ref_ty = self.tcx().mk_ref(deref.region, ty::TypeAndMut {
|
||||
ty: target,
|
||||
mutbl: deref.mutbl,
|
||||
});
|
||||
self.cat_rvalue_node(expr.id, expr.span, ref_ty)
|
||||
} else {
|
||||
previous()?
|
||||
};
|
||||
self.cat_deref(expr, base, false)
|
||||
}
|
||||
|
||||
adjustment::Adjust::NeverToAny |
|
||||
adjustment::Adjust::ReifyFnPointer |
|
||||
adjustment::Adjust::UnsafeFnPointer |
|
||||
adjustment::Adjust::ClosureFnPointer |
|
||||
adjustment::Adjust::MutToConstPointer |
|
||||
adjustment::Adjust::Borrow(_) |
|
||||
adjustment::Adjust::Unsize => {
|
||||
// Result is an rvalue.
|
||||
Ok(self.cat_rvalue_node(expr.id, expr.span, target))
|
||||
}
|
||||
}
|
||||
return Ok(cmt);
|
||||
}
|
||||
|
||||
pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
|
||||
@ -528,8 +532,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
let expr_ty = self.expr_ty(expr)?;
|
||||
match expr.node {
|
||||
hir::ExprUnary(hir::UnDeref, ref e_base) => {
|
||||
let base_cmt = self.cat_expr(&e_base)?;
|
||||
self.cat_deref(expr, base_cmt, 0)
|
||||
if self.infcx.tables.borrow().is_method_call(expr) {
|
||||
self.cat_overloaded_lvalue(expr, e_base, false)
|
||||
} else {
|
||||
let base_cmt = self.cat_expr(&e_base)?;
|
||||
self.cat_deref(expr, base_cmt, false)
|
||||
}
|
||||
}
|
||||
|
||||
hir::ExprField(ref base, f_name) => {
|
||||
@ -547,33 +555,16 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
hir::ExprIndex(ref base, _) => {
|
||||
let method_call = ty::MethodCall::expr(expr.id());
|
||||
match self.infcx.node_method_ty(method_call) {
|
||||
Some(method_ty) => {
|
||||
// If this is an index implemented by a method call, then it
|
||||
// will include an implicit deref of the result.
|
||||
let ret_ty = self.overloaded_method_return_ty(method_ty);
|
||||
|
||||
// The index method always returns an `&T`, so
|
||||
// dereference it to find the result type.
|
||||
let elem_ty = match ret_ty.sty {
|
||||
ty::TyRef(_, mt) => mt.ty,
|
||||
_ => {
|
||||
debug!("cat_expr_unadjusted: return type of overloaded index is {:?}?",
|
||||
ret_ty);
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
||||
// The call to index() returns a `&T` value, which
|
||||
// is an rvalue. That is what we will be
|
||||
// dereferencing.
|
||||
let base_cmt = self.cat_rvalue_node(expr.id(), expr.span(), ret_ty);
|
||||
Ok(self.cat_deref_common(expr, base_cmt, 1, elem_ty, true))
|
||||
}
|
||||
None => {
|
||||
self.cat_index(expr, self.cat_expr(&base)?, InteriorOffsetKind::Index)
|
||||
}
|
||||
if self.infcx.tables.borrow().is_method_call(expr) {
|
||||
// If this is an index implemented by a method call, then it
|
||||
// will include an implicit deref of the result.
|
||||
// The call to index() returns a `&T` value, which
|
||||
// is an rvalue. That is what we will be
|
||||
// dereferencing.
|
||||
self.cat_overloaded_lvalue(expr, base, true)
|
||||
} else {
|
||||
let base_cmt = self.cat_expr(&base)?;
|
||||
self.cat_index(expr, base_cmt, expr_ty, InteriorOffsetKind::Index)
|
||||
}
|
||||
}
|
||||
|
||||
@ -763,7 +754,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
cmt_ {
|
||||
id: id,
|
||||
span: span,
|
||||
cat: Categorization::Deref(Rc::new(cmt_result), 0, ptr),
|
||||
cat: Categorization::Deref(Rc::new(cmt_result), ptr),
|
||||
mutbl: MutabilityCategory::from_borrow_kind(upvar_borrow.kind),
|
||||
ty: var_ty,
|
||||
note: NoteUpvarRef(upvar_id)
|
||||
@ -823,7 +814,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
let ret = cmt_ {
|
||||
id: id,
|
||||
span: span,
|
||||
cat: Categorization::Deref(Rc::new(cmt_result), 0, env_ptr),
|
||||
cat: Categorization::Deref(Rc::new(cmt_result), env_ptr),
|
||||
mutbl: deref_mutbl,
|
||||
ty: var_ty,
|
||||
note: NoteClosureEnv(upvar_id)
|
||||
@ -932,51 +923,51 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
ret
|
||||
}
|
||||
|
||||
fn cat_deref<N:ast_node>(&self,
|
||||
node: &N,
|
||||
base_cmt: cmt<'tcx>,
|
||||
deref_cnt: usize)
|
||||
fn cat_overloaded_lvalue(&self,
|
||||
expr: &hir::Expr,
|
||||
base: &hir::Expr,
|
||||
implicit: bool)
|
||||
-> McResult<cmt<'tcx>> {
|
||||
let method_call = ty::MethodCall {
|
||||
expr_id: node.id(),
|
||||
autoderef: deref_cnt as u32
|
||||
};
|
||||
let method_ty = self.infcx.node_method_ty(method_call);
|
||||
debug!("cat_overloaded_lvalue: implicit={}", implicit);
|
||||
|
||||
debug!("cat_deref: method_call={:?} method_ty={:?}",
|
||||
method_call, method_ty.map(|ty| ty));
|
||||
// Reconstruct the output assuming it's a reference with the
|
||||
// same region and mutability as the receiver. This holds for
|
||||
// `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
|
||||
let lvalue_ty = self.expr_ty(expr)?;
|
||||
let base_ty = self.expr_ty_adjusted(base)?;
|
||||
|
||||
let base_cmt = match method_ty {
|
||||
Some(method_ty) => {
|
||||
let ref_ty =
|
||||
self.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap();
|
||||
self.cat_rvalue_node(node.id(), node.span(), ref_ty)
|
||||
let (region, mutbl) = match base_ty.sty {
|
||||
ty::TyRef(region, mt) => (region, mt.mutbl),
|
||||
_ => {
|
||||
span_bug!(expr.span, "cat_overloaded_lvalue: base is not a reference")
|
||||
}
|
||||
None => base_cmt
|
||||
};
|
||||
let ref_ty = self.tcx().mk_ref(region, ty::TypeAndMut {
|
||||
ty: lvalue_ty,
|
||||
mutbl,
|
||||
});
|
||||
|
||||
let base_cmt = self.cat_rvalue_node(expr.id, expr.span, ref_ty);
|
||||
self.cat_deref(expr, base_cmt, implicit)
|
||||
}
|
||||
|
||||
pub fn cat_deref<N:ast_node>(&self,
|
||||
node: &N,
|
||||
base_cmt: cmt<'tcx>,
|
||||
implicit: bool)
|
||||
-> McResult<cmt<'tcx>> {
|
||||
debug!("cat_deref: base_cmt={:?}", base_cmt);
|
||||
|
||||
let base_cmt_ty = base_cmt.ty;
|
||||
match base_cmt_ty.builtin_deref(true, ty::NoPreference) {
|
||||
Some(mt) => {
|
||||
let ret = self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty, false);
|
||||
debug!("cat_deref ret {:?}", ret);
|
||||
Ok(ret)
|
||||
}
|
||||
let deref_ty = match base_cmt_ty.builtin_deref(true, ty::NoPreference) {
|
||||
Some(mt) => mt.ty,
|
||||
None => {
|
||||
debug!("Explicit deref of non-derefable type: {:?}",
|
||||
base_cmt_ty);
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fn cat_deref_common<N:ast_node>(&self,
|
||||
node: &N,
|
||||
base_cmt: cmt<'tcx>,
|
||||
deref_cnt: usize,
|
||||
deref_ty: Ty<'tcx>,
|
||||
implicit: bool)
|
||||
-> cmt<'tcx>
|
||||
{
|
||||
let ptr = match base_cmt.ty.sty {
|
||||
ty::TyAdt(def, ..) if def.is_box() => Unique,
|
||||
ty::TyRawPtr(ref mt) => UnsafePtr(mt.mutbl),
|
||||
@ -984,26 +975,27 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
let bk = ty::BorrowKind::from_mutbl(mt.mutbl);
|
||||
if implicit { Implicit(bk, r) } else { BorrowedPtr(bk, r) }
|
||||
}
|
||||
ref ty => bug!("unexpected type in cat_deref_common: {:?}", ty)
|
||||
ref ty => bug!("unexpected type in cat_deref: {:?}", ty)
|
||||
};
|
||||
let ret = Rc::new(cmt_ {
|
||||
id: node.id(),
|
||||
span: node.span(),
|
||||
// For unique ptrs, we inherit mutability from the owning reference.
|
||||
mutbl: MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr),
|
||||
cat: Categorization::Deref(base_cmt, deref_cnt, ptr),
|
||||
cat: Categorization::Deref(base_cmt, ptr),
|
||||
ty: deref_ty,
|
||||
note: NoteNone
|
||||
});
|
||||
debug!("cat_deref_common ret {:?}", ret);
|
||||
ret
|
||||
debug!("cat_deref ret {:?}", ret);
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
pub fn cat_index<N:ast_node>(&self,
|
||||
elt: &N,
|
||||
mut base_cmt: cmt<'tcx>,
|
||||
context: InteriorOffsetKind)
|
||||
-> McResult<cmt<'tcx>> {
|
||||
fn cat_index<N:ast_node>(&self,
|
||||
elt: &N,
|
||||
base_cmt: cmt<'tcx>,
|
||||
element_ty: Ty<'tcx>,
|
||||
context: InteriorOffsetKind)
|
||||
-> McResult<cmt<'tcx>> {
|
||||
//! Creates a cmt for an indexing operation (`[]`).
|
||||
//!
|
||||
//! One subtle aspect of indexing that may not be
|
||||
@ -1021,31 +1013,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
//! - `elt`: the AST node being indexed
|
||||
//! - `base_cmt`: the cmt of `elt`
|
||||
|
||||
let method_call = ty::MethodCall::expr(elt.id());
|
||||
let method_ty = self.infcx.node_method_ty(method_call);
|
||||
|
||||
let (element_ty, element_kind) = match method_ty {
|
||||
Some(method_ty) => {
|
||||
let ref_ty = self.overloaded_method_return_ty(method_ty);
|
||||
base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty);
|
||||
|
||||
(ref_ty.builtin_deref(false, ty::NoPreference).unwrap().ty,
|
||||
ElementKind::OtherElement)
|
||||
}
|
||||
None => {
|
||||
match base_cmt.ty.builtin_index() {
|
||||
Some(ty) => (ty, ElementKind::VecElement),
|
||||
None => {
|
||||
debug!("Explicit index of non-indexable type {:?}", base_cmt);
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let interior_elem = InteriorElement(context, element_kind);
|
||||
let interior_elem = InteriorElement(context);
|
||||
let ret =
|
||||
self.cat_imm_interior(elt, base_cmt.clone(), element_ty, interior_elem);
|
||||
self.cat_imm_interior(elt, base_cmt, element_ty, interior_elem);
|
||||
debug!("cat_index ret {:?}", ret);
|
||||
return Ok(ret);
|
||||
}
|
||||
@ -1235,13 +1205,20 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
// box p1, &p1, &mut p1. we can ignore the mutability of
|
||||
// PatKind::Ref since that information is already contained
|
||||
// in the type.
|
||||
let subcmt = self.cat_deref(pat, cmt, 0)?;
|
||||
let subcmt = self.cat_deref(pat, cmt, false)?;
|
||||
self.cat_pattern_(subcmt, &subpat, op)?;
|
||||
}
|
||||
|
||||
PatKind::Slice(ref before, ref slice, ref after) => {
|
||||
let element_ty = match cmt.ty.builtin_index() {
|
||||
Some(ty) => ty,
|
||||
None => {
|
||||
debug!("Explicit index of non-indexable type {:?}", cmt);
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
let context = InteriorOffsetKind::Pattern;
|
||||
let elt_cmt = self.cat_index(pat, cmt, context)?;
|
||||
let elt_cmt = self.cat_index(pat, cmt, element_ty, context)?;
|
||||
for before_pat in before {
|
||||
self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?;
|
||||
}
|
||||
@ -1261,19 +1238,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn overloaded_method_return_ty(&self,
|
||||
method_ty: Ty<'tcx>)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
// When we process an overloaded `*` or `[]` etc, we often
|
||||
// need to extract the return type of the method. These method
|
||||
// types are generated by method resolution and always have
|
||||
// all late-bound regions fully instantiated, so we just want
|
||||
// to skip past the binder.
|
||||
self.tcx().no_late_bound_regions(&method_ty.fn_ret())
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -1300,15 +1264,15 @@ impl<'tcx> cmt_<'tcx> {
|
||||
Categorization::Rvalue(..) |
|
||||
Categorization::StaticItem |
|
||||
Categorization::Local(..) |
|
||||
Categorization::Deref(.., UnsafePtr(..)) |
|
||||
Categorization::Deref(.., BorrowedPtr(..)) |
|
||||
Categorization::Deref(.., Implicit(..)) |
|
||||
Categorization::Deref(_, UnsafePtr(..)) |
|
||||
Categorization::Deref(_, BorrowedPtr(..)) |
|
||||
Categorization::Deref(_, Implicit(..)) |
|
||||
Categorization::Upvar(..) => {
|
||||
Rc::new((*self).clone())
|
||||
}
|
||||
Categorization::Downcast(ref b, _) |
|
||||
Categorization::Interior(ref b, _) |
|
||||
Categorization::Deref(ref b, _, Unique) => {
|
||||
Categorization::Deref(ref b, Unique) => {
|
||||
b.guarantor()
|
||||
}
|
||||
}
|
||||
@ -1321,11 +1285,11 @@ impl<'tcx> cmt_<'tcx> {
|
||||
// aliased and eventually recused.
|
||||
|
||||
match self.cat {
|
||||
Categorization::Deref(ref b, _, BorrowedPtr(ty::MutBorrow, _)) |
|
||||
Categorization::Deref(ref b, _, Implicit(ty::MutBorrow, _)) |
|
||||
Categorization::Deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) |
|
||||
Categorization::Deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) |
|
||||
Categorization::Deref(ref b, _, Unique) |
|
||||
Categorization::Deref(ref b, BorrowedPtr(ty::MutBorrow, _)) |
|
||||
Categorization::Deref(ref b, Implicit(ty::MutBorrow, _)) |
|
||||
Categorization::Deref(ref b, BorrowedPtr(ty::UniqueImmBorrow, _)) |
|
||||
Categorization::Deref(ref b, Implicit(ty::UniqueImmBorrow, _)) |
|
||||
Categorization::Deref(ref b, Unique) |
|
||||
Categorization::Downcast(ref b, _) |
|
||||
Categorization::Interior(ref b, _) => {
|
||||
// Aliasability depends on base cmt
|
||||
@ -1335,7 +1299,7 @@ impl<'tcx> cmt_<'tcx> {
|
||||
Categorization::Rvalue(..) |
|
||||
Categorization::Local(..) |
|
||||
Categorization::Upvar(..) |
|
||||
Categorization::Deref(.., UnsafePtr(..)) => { // yes, it's aliasable, but...
|
||||
Categorization::Deref(_, UnsafePtr(..)) => { // yes, it's aliasable, but...
|
||||
NonAliasable
|
||||
}
|
||||
|
||||
@ -1347,8 +1311,8 @@ impl<'tcx> cmt_<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
Categorization::Deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) |
|
||||
Categorization::Deref(_, _, Implicit(ty::ImmBorrow, _)) => {
|
||||
Categorization::Deref(_, BorrowedPtr(ty::ImmBorrow, _)) |
|
||||
Categorization::Deref(_, Implicit(ty::ImmBorrow, _)) => {
|
||||
FreelyAliasable(AliasableBorrowed)
|
||||
}
|
||||
}
|
||||
@ -1360,9 +1324,9 @@ impl<'tcx> cmt_<'tcx> {
|
||||
match self.note {
|
||||
NoteClosureEnv(..) | NoteUpvarRef(..) => {
|
||||
Some(match self.cat {
|
||||
Categorization::Deref(ref inner, ..) => {
|
||||
Categorization::Deref(ref inner, _) => {
|
||||
match inner.cat {
|
||||
Categorization::Deref(ref inner, ..) => inner.clone(),
|
||||
Categorization::Deref(ref inner, _) => inner.clone(),
|
||||
Categorization::Upvar(..) => inner.clone(),
|
||||
_ => bug!()
|
||||
}
|
||||
@ -1390,7 +1354,7 @@ impl<'tcx> cmt_<'tcx> {
|
||||
"local variable".to_string()
|
||||
}
|
||||
}
|
||||
Categorization::Deref(.., pk) => {
|
||||
Categorization::Deref(_, pk) => {
|
||||
let upvar = self.upvar();
|
||||
match upvar.as_ref().map(|i| &i.cat) {
|
||||
Some(&Categorization::Upvar(ref var)) => {
|
||||
@ -1421,16 +1385,10 @@ impl<'tcx> cmt_<'tcx> {
|
||||
Categorization::Interior(_, InteriorField(PositionalField(_))) => {
|
||||
"anonymous field".to_string()
|
||||
}
|
||||
Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index,
|
||||
VecElement)) |
|
||||
Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index,
|
||||
OtherElement)) => {
|
||||
Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index)) => {
|
||||
"indexed content".to_string()
|
||||
}
|
||||
Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern,
|
||||
VecElement)) |
|
||||
Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern,
|
||||
OtherElement)) => {
|
||||
Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern)) => {
|
||||
"pattern-bound indexed content".to_string()
|
||||
}
|
||||
Categorization::Upvar(ref var) => {
|
||||
@ -1467,8 +1425,8 @@ impl<'tcx> fmt::Debug for Categorization<'tcx> {
|
||||
Categorization::Upvar(upvar) => {
|
||||
write!(f, "upvar({:?})", upvar)
|
||||
}
|
||||
Categorization::Deref(ref cmt, derefs, ptr) => {
|
||||
write!(f, "{:?}-{:?}{}->", cmt.cat, ptr, derefs)
|
||||
Categorization::Deref(ref cmt, ptr) => {
|
||||
write!(f, "{:?}-{:?}->", cmt.cat, ptr)
|
||||
}
|
||||
Categorization::Interior(ref cmt, interior) => {
|
||||
write!(f, "{:?}.{:?}", cmt.cat, interior)
|
||||
|
@ -110,9 +110,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> {
|
||||
Some(self.tables.qpath_def(qpath, expr.id))
|
||||
}
|
||||
hir::ExprMethodCall(..) => {
|
||||
let method_call = ty::MethodCall::expr(expr.id);
|
||||
let def_id = self.tables.method_map[&method_call].def_id;
|
||||
Some(Def::Method(def_id))
|
||||
Some(self.tables.type_dependent_defs[&expr.id])
|
||||
}
|
||||
_ => None
|
||||
};
|
||||
|
@ -8,21 +8,59 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use ty::{self, Ty, TyCtxt, TypeAndMut};
|
||||
use ty::LvaluePreference::{NoPreference};
|
||||
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use hir;
|
||||
use hir::def_id::DefId;
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::subst::Substs;
|
||||
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
|
||||
|
||||
/// Represents coercing a value to a different type of value.
|
||||
///
|
||||
/// We transform values by following a number of `Adjust` steps in order.
|
||||
/// See the documentation on variants of `Adjust` for more details.
|
||||
///
|
||||
/// Here are some common scenarios:
|
||||
///
|
||||
/// 1. The simplest cases are where a pointer is not adjusted fat vs thin.
|
||||
/// Here the pointer will be dereferenced N times (where a dereference can
|
||||
/// happen to raw or borrowed pointers or any smart pointer which implements
|
||||
/// Deref, including Box<_>). The types of dereferences is given by
|
||||
/// `autoderefs`. It can then be auto-referenced zero or one times, indicated
|
||||
/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
|
||||
/// `false`.
|
||||
///
|
||||
/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start
|
||||
/// with a thin pointer, deref a number of times, unsize the underlying data,
|
||||
/// then autoref. The 'unsize' phase may change a fixed length array to a
|
||||
/// dynamically sized one, a concrete object to a trait object, or statically
|
||||
/// sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is
|
||||
/// represented by:
|
||||
///
|
||||
/// ```
|
||||
/// Deref(None) -> [i32; 4],
|
||||
/// Borrow(AutoBorrow::Ref) -> &[i32; 4],
|
||||
/// Unsize -> &[i32],
|
||||
/// ```
|
||||
///
|
||||
/// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
|
||||
/// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
|
||||
/// The autoderef and -ref are the same as in the above example, but the type
|
||||
/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
|
||||
/// the underlying conversions from `[i32; 4]` to `[i32]`.
|
||||
///
|
||||
/// 3. Coercing a `Box<T>` to `Box<Trait>` is an interesting special case. In
|
||||
/// that case, we have the pointer we need coming in, so there are no
|
||||
/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
|
||||
/// At some point, of course, `Box` should move out of the compiler, in which
|
||||
/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> ->
|
||||
/// Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
||||
pub struct Adjustment<'tcx> {
|
||||
pub kind: Adjust<'tcx>,
|
||||
pub target: Ty<'tcx>
|
||||
pub target: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum Adjust<'tcx> {
|
||||
/// Go from ! to any type.
|
||||
NeverToAny,
|
||||
@ -39,94 +77,45 @@ pub enum Adjust<'tcx> {
|
||||
/// Go from a mut raw pointer to a const raw pointer.
|
||||
MutToConstPointer,
|
||||
|
||||
/// Represents coercing a pointer to a different kind of pointer - where 'kind'
|
||||
/// here means either or both of raw vs borrowed vs unique and fat vs thin.
|
||||
///
|
||||
/// We transform pointers by following the following steps in order:
|
||||
/// 1. Deref the pointer `self.autoderefs` times (may be 0).
|
||||
/// 2. If `autoref` is `Some(_)`, then take the address and produce either a
|
||||
/// `&` or `*` pointer.
|
||||
/// 3. If `unsize` is `Some(_)`, then apply the unsize transformation,
|
||||
/// which will do things like convert thin pointers to fat
|
||||
/// pointers, or convert structs containing thin pointers to
|
||||
/// structs containing fat pointers, or convert between fat
|
||||
/// pointers. We don't store the details of how the transform is
|
||||
/// done (in fact, we don't know that, because it might depend on
|
||||
/// the precise type parameters). We just store the target
|
||||
/// type. Trans figures out what has to be done at monomorphization
|
||||
/// time based on the precise source/target type at hand.
|
||||
///
|
||||
/// To make that more concrete, here are some common scenarios:
|
||||
///
|
||||
/// 1. The simplest cases are where the pointer is not adjusted fat vs thin.
|
||||
/// Here the pointer will be dereferenced N times (where a dereference can
|
||||
/// happen to raw or borrowed pointers or any smart pointer which implements
|
||||
/// Deref, including Box<_>). The number of dereferences is given by
|
||||
/// `autoderefs`. It can then be auto-referenced zero or one times, indicated
|
||||
/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
|
||||
/// None.
|
||||
///
|
||||
/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start
|
||||
/// with a thin pointer, deref a number of times, unsize the underlying data,
|
||||
/// then autoref. The 'unsize' phase may change a fixed length array to a
|
||||
/// dynamically sized one, a concrete object to a trait object, or statically
|
||||
/// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is
|
||||
/// represented by:
|
||||
///
|
||||
/// ```
|
||||
/// Adjust::DerefRef {
|
||||
/// autoderefs: 1, // &[i32; 4] -> [i32; 4]
|
||||
/// autoref: Some(AutoBorrow::Ref), // [i32] -> &[i32]
|
||||
/// unsize: Some([i32]), // [i32; 4] -> [i32]
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
|
||||
/// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
|
||||
/// The autoderef and -ref are the same as in the above example, but the type
|
||||
/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
|
||||
/// the underlying conversions from `[i32; 4]` to `[i32]`.
|
||||
///
|
||||
/// 3. Coercing a `Box<T>` to `Box<Trait>` is an interesting special case. In
|
||||
/// that case, we have the pointer we need coming in, so there are no
|
||||
/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
|
||||
/// At some point, of course, `Box` should move out of the compiler, in which
|
||||
/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> ->
|
||||
/// Box<[i32]> is represented by:
|
||||
///
|
||||
/// ```
|
||||
/// Adjust::DerefRef {
|
||||
/// autoderefs: 0,
|
||||
/// autoref: None,
|
||||
/// unsize: Some(Box<[i32]>),
|
||||
/// }
|
||||
/// ```
|
||||
DerefRef {
|
||||
/// Step 1. Apply a number of dereferences, producing an lvalue.
|
||||
autoderefs: usize,
|
||||
/// Dereference once, producing an lvalue.
|
||||
Deref(Option<OverloadedDeref<'tcx>>),
|
||||
|
||||
/// Step 2. Optionally produce a pointer/reference from the value.
|
||||
autoref: Option<AutoBorrow<'tcx>>,
|
||||
/// Take the address and produce either a `&` or `*` pointer.
|
||||
Borrow(AutoBorrow<'tcx>),
|
||||
|
||||
/// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to
|
||||
/// `&[T]`. Note that the source could be a thin or fat pointer.
|
||||
unsize: bool,
|
||||
}
|
||||
/// Unsize a pointer/reference value, e.g. `&[T; n]` to
|
||||
/// `&[T]`. Note that the source could be a thin or fat pointer.
|
||||
/// This will do things like convert thin pointers to fat
|
||||
/// pointers, or convert structs containing thin pointers to
|
||||
/// structs containing fat pointers, or convert between fat
|
||||
/// pointers. We don't store the details of how the transform is
|
||||
/// done (in fact, we don't know that, because it might depend on
|
||||
/// the precise type parameters). We just store the target
|
||||
/// type. Trans figures out what has to be done at monomorphization
|
||||
/// time based on the precise source/target type at hand.
|
||||
Unsize,
|
||||
}
|
||||
|
||||
impl<'tcx> Adjustment<'tcx> {
|
||||
pub fn is_identity(&self) -> bool {
|
||||
match self.kind {
|
||||
Adjust::NeverToAny => self.target.is_never(),
|
||||
/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
|
||||
/// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`.
|
||||
/// The target type is `U` in both cases, with the region and mutability
|
||||
/// being those shared by both the receiver and the returned reference.
|
||||
#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct OverloadedDeref<'tcx> {
|
||||
pub region: ty::Region<'tcx>,
|
||||
pub mutbl: hir::Mutability,
|
||||
}
|
||||
|
||||
Adjust::DerefRef { autoderefs: 0, autoref: None, unsize: false } => true,
|
||||
|
||||
Adjust::ReifyFnPointer |
|
||||
Adjust::UnsafeFnPointer |
|
||||
Adjust::ClosureFnPointer |
|
||||
Adjust::MutToConstPointer |
|
||||
Adjust::DerefRef {..} => false,
|
||||
}
|
||||
impl<'a, 'gcx, 'tcx> OverloadedDeref<'tcx> {
|
||||
pub fn method_call(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, source: Ty<'tcx>)
|
||||
-> (DefId, &'tcx Substs<'tcx>) {
|
||||
let trait_def_id = match self.mutbl {
|
||||
hir::MutImmutable => tcx.lang_items.deref_trait(),
|
||||
hir::MutMutable => tcx.lang_items.deref_mut_trait()
|
||||
};
|
||||
let method_def_id = tcx.associated_items(trait_def_id.unwrap())
|
||||
.find(|m| m.kind == ty::AssociatedKind::Method).unwrap().def_id;
|
||||
(method_def_id, tcx.mk_substs_trait(source, &[]))
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,48 +148,3 @@ pub enum CustomCoerceUnsized {
|
||||
/// Records the index of the field being coerced.
|
||||
Struct(usize)
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> {
|
||||
pub fn adjust_for_autoderef<F>(&'tcx self,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
expr_id: ast::NodeId,
|
||||
expr_span: Span,
|
||||
autoderef: u32, // how many autoderefs so far?
|
||||
mut method_type: F)
|
||||
-> Ty<'tcx> where
|
||||
F: FnMut(ty::MethodCall) -> Option<Ty<'tcx>>,
|
||||
{
|
||||
let method_call = ty::MethodCall::autoderef(expr_id, autoderef);
|
||||
let mut adjusted_ty = self;
|
||||
if let Some(method_ty) = method_type(method_call) {
|
||||
// Method calls always have all late-bound regions
|
||||
// fully instantiated.
|
||||
adjusted_ty = tcx.no_late_bound_regions(&method_ty.fn_ret()).unwrap();
|
||||
}
|
||||
match adjusted_ty.builtin_deref(true, NoPreference) {
|
||||
Some(mt) => mt.ty,
|
||||
None => {
|
||||
span_bug!(
|
||||
expr_span,
|
||||
"the {}th autoderef for {} failed: {}",
|
||||
autoderef,
|
||||
expr_id,
|
||||
adjusted_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn adjust_for_autoref(&'tcx self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
autoref: Option<AutoBorrow<'tcx>>)
|
||||
-> Ty<'tcx> {
|
||||
match autoref {
|
||||
None => self,
|
||||
Some(AutoBorrow::Ref(r, m)) => {
|
||||
tcx.mk_ref(r, TypeAndMut { ty: self, mutbl: m })
|
||||
}
|
||||
Some(AutoBorrow::RawPtr(m)) => {
|
||||
tcx.mk_ptr(TypeAndMut { ty: self, mutbl: m })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -206,8 +206,9 @@ pub struct CommonTypes<'tcx> {
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct TypeckTables<'tcx> {
|
||||
/// Resolved definitions for `<T>::X` associated paths.
|
||||
pub type_relative_path_defs: NodeMap<Def>,
|
||||
/// Resolved definitions for `<T>::X` associated paths and
|
||||
/// method calls, including those of overloaded operators.
|
||||
pub type_dependent_defs: NodeMap<Def>,
|
||||
|
||||
/// Stores the types for various nodes in the AST. Note that this table
|
||||
/// is not guaranteed to be populated until after typeck. See
|
||||
@ -218,11 +219,9 @@ pub struct TypeckTables<'tcx> {
|
||||
/// of this node. This only applies to nodes that refer to entities
|
||||
/// parameterized by type parameters, such as generic fns, types, or
|
||||
/// other items.
|
||||
pub item_substs: NodeMap<ty::ItemSubsts<'tcx>>,
|
||||
pub node_substs: NodeMap<&'tcx Substs<'tcx>>,
|
||||
|
||||
pub adjustments: NodeMap<ty::adjustment::Adjustment<'tcx>>,
|
||||
|
||||
pub method_map: ty::MethodMap<'tcx>,
|
||||
pub adjustments: NodeMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
|
||||
|
||||
/// Borrows
|
||||
pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
|
||||
@ -271,11 +270,10 @@ pub struct TypeckTables<'tcx> {
|
||||
impl<'tcx> TypeckTables<'tcx> {
|
||||
pub fn empty() -> TypeckTables<'tcx> {
|
||||
TypeckTables {
|
||||
type_relative_path_defs: NodeMap(),
|
||||
type_dependent_defs: NodeMap(),
|
||||
node_types: FxHashMap(),
|
||||
item_substs: NodeMap(),
|
||||
node_substs: NodeMap(),
|
||||
adjustments: NodeMap(),
|
||||
method_map: FxHashMap(),
|
||||
upvar_capture_map: FxHashMap(),
|
||||
closure_tys: NodeMap(),
|
||||
closure_kinds: NodeMap(),
|
||||
@ -294,7 +292,7 @@ impl<'tcx> TypeckTables<'tcx> {
|
||||
match *qpath {
|
||||
hir::QPath::Resolved(_, ref path) => path.def,
|
||||
hir::QPath::TypeRelative(..) => {
|
||||
self.type_relative_path_defs.get(&id).cloned().unwrap_or(Def::Err)
|
||||
self.type_dependent_defs.get(&id).cloned().unwrap_or(Def::Err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -313,8 +311,8 @@ impl<'tcx> TypeckTables<'tcx> {
|
||||
self.node_types.get(&id).cloned()
|
||||
}
|
||||
|
||||
pub fn node_id_item_substs(&self, id: NodeId) -> Option<&'tcx Substs<'tcx>> {
|
||||
self.item_substs.get(&id).map(|ts| ts.substs)
|
||||
pub fn node_substs(&self, id: NodeId) -> &'tcx Substs<'tcx> {
|
||||
self.node_substs.get(&id).cloned().unwrap_or(Substs::empty())
|
||||
}
|
||||
|
||||
// Returns the type of a pattern as a monotype. Like @expr_ty, this function
|
||||
@ -345,24 +343,37 @@ impl<'tcx> TypeckTables<'tcx> {
|
||||
self.node_id_to_type_opt(expr.id)
|
||||
}
|
||||
|
||||
pub fn expr_adjustments(&self, expr: &hir::Expr)
|
||||
-> &[ty::adjustment::Adjustment<'tcx>] {
|
||||
self.adjustments.get(&expr.id).map_or(&[], |a| &a[..])
|
||||
}
|
||||
|
||||
/// Returns the type of `expr`, considering any `Adjustment`
|
||||
/// entry recorded for that expression.
|
||||
pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> Ty<'tcx> {
|
||||
self.adjustments.get(&expr.id)
|
||||
self.expr_adjustments(expr)
|
||||
.last()
|
||||
.map_or_else(|| self.expr_ty(expr), |adj| adj.target)
|
||||
}
|
||||
|
||||
pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr) -> Option<Ty<'tcx>> {
|
||||
self.adjustments.get(&expr.id)
|
||||
.map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr))
|
||||
self.expr_adjustments(expr)
|
||||
.last()
|
||||
.map(|adj| adj.target)
|
||||
.or_else(|| self.expr_ty_opt(expr))
|
||||
}
|
||||
|
||||
pub fn is_method_call(&self, expr_id: NodeId) -> bool {
|
||||
self.method_map.contains_key(&ty::MethodCall::expr(expr_id))
|
||||
}
|
||||
pub fn is_method_call(&self, expr: &hir::Expr) -> bool {
|
||||
// Only paths and method calls/overloaded operators have
|
||||
// entries in type_dependent_defs, ignore the former here.
|
||||
if let hir::ExprPath(_) = expr.node {
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn is_overloaded_autoderef(&self, expr_id: NodeId, autoderefs: u32) -> bool {
|
||||
self.method_map.contains_key(&ty::MethodCall::autoderef(expr_id, autoderefs))
|
||||
match self.type_dependent_defs.get(&expr.id) {
|
||||
Some(&Def::Method(_)) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
|
||||
|
@ -39,8 +39,6 @@
|
||||
//! These methods return true to indicate that the visitor has found what it is looking for
|
||||
//! and does not need to visit anything else.
|
||||
|
||||
use ty::subst::Substs;
|
||||
use ty::adjustment;
|
||||
use ty::{self, Binder, Ty, TyCtxt, TypeFlags};
|
||||
|
||||
use std::fmt;
|
||||
@ -138,34 +136,9 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized {
|
||||
t.super_fold_with(self)
|
||||
}
|
||||
|
||||
fn fold_mt(&mut self, t: &ty::TypeAndMut<'tcx>) -> ty::TypeAndMut<'tcx> {
|
||||
t.super_fold_with(self)
|
||||
}
|
||||
|
||||
fn fold_impl_header(&mut self, imp: &ty::ImplHeader<'tcx>) -> ty::ImplHeader<'tcx> {
|
||||
imp.super_fold_with(self)
|
||||
}
|
||||
|
||||
fn fold_substs(&mut self,
|
||||
substs: &'tcx Substs<'tcx>)
|
||||
-> &'tcx Substs<'tcx> {
|
||||
substs.super_fold_with(self)
|
||||
}
|
||||
|
||||
fn fold_fn_sig(&mut self,
|
||||
sig: &ty::FnSig<'tcx>)
|
||||
-> ty::FnSig<'tcx> {
|
||||
sig.super_fold_with(self)
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
r.super_fold_with(self)
|
||||
}
|
||||
|
||||
fn fold_autoref(&mut self, ar: &adjustment::AutoBorrow<'tcx>)
|
||||
-> adjustment::AutoBorrow<'tcx> {
|
||||
ar.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TypeVisitor<'tcx> : Sized {
|
||||
|
@ -390,52 +390,6 @@ impl Variance {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, RustcDecodable, RustcEncodable)]
|
||||
pub struct MethodCallee<'tcx> {
|
||||
/// Impl method ID, for inherent methods, or trait method ID, otherwise.
|
||||
pub def_id: DefId,
|
||||
pub ty: Ty<'tcx>,
|
||||
pub substs: &'tcx Substs<'tcx>
|
||||
}
|
||||
|
||||
/// With method calls, we store some extra information in
|
||||
/// side tables (i.e method_map). We use
|
||||
/// MethodCall as a key to index into these tables instead of
|
||||
/// just directly using the expression's NodeId. The reason
|
||||
/// for this being that we may apply adjustments (coercions)
|
||||
/// with the resulting expression also needing to use the
|
||||
/// side tables. The problem with this is that we don't
|
||||
/// assign a separate NodeId to this new expression
|
||||
/// and so it would clash with the base expression if both
|
||||
/// needed to add to the side tables. Thus to disambiguate
|
||||
/// we also keep track of whether there's an adjustment in
|
||||
/// our key.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct MethodCall {
|
||||
pub expr_id: NodeId,
|
||||
pub autoderef: u32
|
||||
}
|
||||
|
||||
impl MethodCall {
|
||||
pub fn expr(id: NodeId) -> MethodCall {
|
||||
MethodCall {
|
||||
expr_id: id,
|
||||
autoderef: 0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn autoderef(expr_id: NodeId, autoderef: u32) -> MethodCall {
|
||||
MethodCall {
|
||||
expr_id: expr_id,
|
||||
autoderef: 1 + autoderef
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// maps from an expression id that corresponds to a method call to the details
|
||||
// of the method to be invoked
|
||||
pub type MethodMap<'tcx> = FxHashMap<MethodCall, MethodCallee<'tcx>>;
|
||||
|
||||
// Contains information needed to resolve types and (in the future) look up
|
||||
// the types of AST nodes.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
@ -1843,13 +1797,6 @@ impl<'a, 'gcx, 'tcx> FieldDef {
|
||||
}
|
||||
}
|
||||
|
||||
/// Records the substitutions used to translate the polytype for an
|
||||
/// item into the monotype of an item reference.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
||||
pub struct ItemSubsts<'tcx> {
|
||||
pub substs: &'tcx Substs<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum ClosureKind {
|
||||
// Warning: Ordering is significant here! The ordering is chosen
|
||||
@ -1927,12 +1874,6 @@ impl<'tcx> TyS<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ItemSubsts<'tcx> {
|
||||
pub fn is_noop(&self) -> bool {
|
||||
self.substs.is_noop()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum LvaluePreference {
|
||||
PreferMutLvalue,
|
||||
|
@ -217,12 +217,50 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::ItemSubsts<'a> {
|
||||
type Lifted = ty::ItemSubsts<'tcx>;
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjustment<'a> {
|
||||
type Lifted = ty::adjustment::Adjustment<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
tcx.lift(&self.substs).map(|substs| {
|
||||
ty::ItemSubsts {
|
||||
substs: substs
|
||||
tcx.lift(&self.kind).and_then(|kind| {
|
||||
tcx.lift(&self.target).map(|target| {
|
||||
ty::adjustment::Adjustment { kind, target }
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> {
|
||||
type Lifted = ty::adjustment::Adjust<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
match *self {
|
||||
ty::adjustment::Adjust::NeverToAny =>
|
||||
Some(ty::adjustment::Adjust::NeverToAny),
|
||||
ty::adjustment::Adjust::ReifyFnPointer =>
|
||||
Some(ty::adjustment::Adjust::ReifyFnPointer),
|
||||
ty::adjustment::Adjust::UnsafeFnPointer =>
|
||||
Some(ty::adjustment::Adjust::UnsafeFnPointer),
|
||||
ty::adjustment::Adjust::ClosureFnPointer =>
|
||||
Some(ty::adjustment::Adjust::ClosureFnPointer),
|
||||
ty::adjustment::Adjust::MutToConstPointer =>
|
||||
Some(ty::adjustment::Adjust::MutToConstPointer),
|
||||
ty::adjustment::Adjust::Unsize =>
|
||||
Some(ty::adjustment::Adjust::Unsize),
|
||||
ty::adjustment::Adjust::Deref(ref overloaded) => {
|
||||
tcx.lift(overloaded).map(ty::adjustment::Adjust::Deref)
|
||||
}
|
||||
ty::adjustment::Adjust::Borrow(ref autoref) => {
|
||||
tcx.lift(autoref).map(ty::adjustment::Adjust::Borrow)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> {
|
||||
type Lifted = ty::adjustment::OverloadedDeref<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
tcx.lift(&self.region).map(|region| {
|
||||
ty::adjustment::OverloadedDeref {
|
||||
region,
|
||||
mutbl: self.mutbl,
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -540,10 +578,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
|
||||
ty::TypeAndMut { ty: self.ty.fold_with(folder), mutbl: self.mutbl }
|
||||
}
|
||||
|
||||
fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
folder.fold_mt(self)
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.ty.visit_with(visitor)
|
||||
}
|
||||
@ -560,10 +594,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
folder.fold_fn_sig(self)
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.inputs().iter().any(|i| i.visit_with(visitor)) ||
|
||||
self.output().visit_with(visitor)
|
||||
@ -610,10 +640,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ImplHeader<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
folder.fold_impl_header(self)
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.self_ty.visit_with(visitor) ||
|
||||
self.trait_ref.map(|r| r.visit_with(visitor)).unwrap_or(false) ||
|
||||
@ -651,15 +677,66 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> {
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjustment<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
ty::ItemSubsts {
|
||||
substs: self.substs.fold_with(folder),
|
||||
ty::adjustment::Adjustment {
|
||||
kind: self.kind.fold_with(folder),
|
||||
target: self.target.fold_with(folder),
|
||||
}
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.substs.visit_with(visitor)
|
||||
self.kind.visit_with(visitor) ||
|
||||
self.target.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
match *self {
|
||||
ty::adjustment::Adjust::NeverToAny |
|
||||
ty::adjustment::Adjust::ReifyFnPointer |
|
||||
ty::adjustment::Adjust::UnsafeFnPointer |
|
||||
ty::adjustment::Adjust::ClosureFnPointer |
|
||||
ty::adjustment::Adjust::MutToConstPointer |
|
||||
ty::adjustment::Adjust::Unsize => self.clone(),
|
||||
ty::adjustment::Adjust::Deref(ref overloaded) => {
|
||||
ty::adjustment::Adjust::Deref(overloaded.fold_with(folder))
|
||||
}
|
||||
ty::adjustment::Adjust::Borrow(ref autoref) => {
|
||||
ty::adjustment::Adjust::Borrow(autoref.fold_with(folder))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
match *self {
|
||||
ty::adjustment::Adjust::NeverToAny |
|
||||
ty::adjustment::Adjust::ReifyFnPointer |
|
||||
ty::adjustment::Adjust::UnsafeFnPointer |
|
||||
ty::adjustment::Adjust::ClosureFnPointer |
|
||||
ty::adjustment::Adjust::MutToConstPointer |
|
||||
ty::adjustment::Adjust::Unsize => false,
|
||||
ty::adjustment::Adjust::Deref(ref overloaded) => {
|
||||
overloaded.visit_with(visitor)
|
||||
}
|
||||
ty::adjustment::Adjust::Borrow(ref autoref) => {
|
||||
autoref.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::OverloadedDeref<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
ty::adjustment::OverloadedDeref {
|
||||
region: self.region.fold_with(folder),
|
||||
mutbl: self.mutbl,
|
||||
}
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.region.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
@ -673,10 +750,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
folder.fold_autoref(self)
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
match *self {
|
||||
ty::adjustment::AutoBorrow::Ref(r, _m) => r.visit_with(visitor),
|
||||
|
@ -141,8 +141,6 @@ pub enum TypeVariants<'tcx> {
|
||||
TyFnDef(DefId, &'tcx Substs<'tcx>, PolyFnSig<'tcx>),
|
||||
|
||||
/// A pointer to a function. Written as `fn() -> i32`.
|
||||
/// FIXME: This is currently also used to represent the callee of a method;
|
||||
/// see ty::MethodCallee etc.
|
||||
TyFnPtr(PolyFnSig<'tcx>),
|
||||
|
||||
/// A trait, defined with `trait`.
|
||||
@ -1338,15 +1336,6 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Type accessors for substructures of types
|
||||
pub fn fn_args(&self) -> ty::Binder<&'tcx [Ty<'tcx>]> {
|
||||
self.fn_sig().inputs()
|
||||
}
|
||||
|
||||
pub fn fn_ret(&self) -> Binder<Ty<'tcx>> {
|
||||
self.fn_sig().output()
|
||||
}
|
||||
|
||||
pub fn is_fn(&self) -> bool {
|
||||
match self.sty {
|
||||
TyFnDef(..) | TyFnPtr(_) => true,
|
||||
|
@ -320,10 +320,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
folder.fold_substs(self)
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.iter().any(|t| t.visit_with(visitor))
|
||||
}
|
||||
|
@ -363,12 +363,6 @@ impl<'tcx> fmt::Display for ty::TypeAndMut<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::ItemSubsts<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "ItemSubsts({:?})", self.substs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// when printing out the debug representation, we don't need
|
||||
|
@ -805,7 +805,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||
self.check_if_assigned_path_is_moved(id, span,
|
||||
use_kind, lp_base);
|
||||
}
|
||||
LpExtend(ref lp_base, _, LpInterior(_, InteriorElement(..))) |
|
||||
LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) |
|
||||
LpExtend(ref lp_base, _, LpDeref(_)) => {
|
||||
// assigning to `P[i]` requires `P` is initialized
|
||||
// assigning to `(*P)` requires `P` is initialized
|
||||
|
@ -222,9 +222,9 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||
cmt: &mc::cmt<'tcx>)
|
||||
-> Option<mc::cmt<'tcx>> {
|
||||
match cmt.cat {
|
||||
Categorization::Deref(.., mc::BorrowedPtr(..)) |
|
||||
Categorization::Deref(.., mc::Implicit(..)) |
|
||||
Categorization::Deref(.., mc::UnsafePtr(..)) |
|
||||
Categorization::Deref(_, mc::BorrowedPtr(..)) |
|
||||
Categorization::Deref(_, mc::Implicit(..)) |
|
||||
Categorization::Deref(_, mc::UnsafePtr(..)) |
|
||||
Categorization::StaticItem => {
|
||||
Some(cmt.clone())
|
||||
}
|
||||
@ -237,7 +237,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||
|
||||
Categorization::Downcast(ref b, _) |
|
||||
Categorization::Interior(ref b, mc::InteriorField(_)) |
|
||||
Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => {
|
||||
Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern)) => {
|
||||
match b.ty.sty {
|
||||
ty::TyAdt(def, _) => {
|
||||
if def.has_dtor(bccx.tcx) {
|
||||
@ -253,12 +253,12 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
Categorization::Interior(_, mc::InteriorElement(Kind::Index, _)) => {
|
||||
Categorization::Interior(_, mc::InteriorElement(Kind::Index)) => {
|
||||
// Forbid move of arr[i] for arr: [T; 3]; see RFC 533.
|
||||
Some(cmt.clone())
|
||||
}
|
||||
|
||||
Categorization::Deref(ref b, _, mc::Unique) => {
|
||||
Categorization::Deref(ref b, mc::Unique) => {
|
||||
check_and_get_illegal_move_origin(bccx, b)
|
||||
}
|
||||
}
|
||||
|
@ -72,11 +72,11 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
|
||||
|
||||
match cmt.cat {
|
||||
Categorization::Rvalue(..) |
|
||||
Categorization::Local(..) | // L-Local
|
||||
Categorization::Local(..) | // L-Local
|
||||
Categorization::Upvar(..) |
|
||||
Categorization::Deref(.., mc::BorrowedPtr(..)) | // L-Deref-Borrowed
|
||||
Categorization::Deref(.., mc::Implicit(..)) |
|
||||
Categorization::Deref(.., mc::UnsafePtr(..)) => {
|
||||
Categorization::Deref(_, mc::BorrowedPtr(..)) | // L-Deref-Borrowed
|
||||
Categorization::Deref(_, mc::Implicit(..)) |
|
||||
Categorization::Deref(_, mc::UnsafePtr(..)) => {
|
||||
self.check_scope(self.scope(cmt))
|
||||
}
|
||||
|
||||
@ -85,8 +85,8 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
Categorization::Downcast(ref base, _) |
|
||||
Categorization::Deref(ref base, _, mc::Unique) | // L-Deref-Send
|
||||
Categorization::Interior(ref base, _) => { // L-Field
|
||||
Categorization::Deref(ref base, mc::Unique) | // L-Deref-Send
|
||||
Categorization::Interior(ref base, _) => { // L-Field
|
||||
self.check(base, discr_scope)
|
||||
}
|
||||
}
|
||||
@ -119,15 +119,15 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
|
||||
self.bccx.region_maps.var_scope(local_id)))
|
||||
}
|
||||
Categorization::StaticItem |
|
||||
Categorization::Deref(.., mc::UnsafePtr(..)) => {
|
||||
Categorization::Deref(_, mc::UnsafePtr(..)) => {
|
||||
self.bccx.tcx.types.re_static
|
||||
}
|
||||
Categorization::Deref(.., mc::BorrowedPtr(_, r)) |
|
||||
Categorization::Deref(.., mc::Implicit(_, r)) => {
|
||||
Categorization::Deref(_, mc::BorrowedPtr(_, r)) |
|
||||
Categorization::Deref(_, mc::Implicit(_, r)) => {
|
||||
r
|
||||
}
|
||||
Categorization::Downcast(ref cmt, _) |
|
||||
Categorization::Deref(ref cmt, _, mc::Unique) |
|
||||
Categorization::Deref(ref cmt, mc::Unique) |
|
||||
Categorization::Interior(ref cmt, _) => {
|
||||
self.scope(cmt)
|
||||
}
|
||||
|
@ -138,9 +138,9 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||
move_from: mc::cmt<'tcx>)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
match move_from.cat {
|
||||
Categorization::Deref(.., mc::BorrowedPtr(..)) |
|
||||
Categorization::Deref(.., mc::Implicit(..)) |
|
||||
Categorization::Deref(.., mc::UnsafePtr(..)) |
|
||||
Categorization::Deref(_, mc::BorrowedPtr(..)) |
|
||||
Categorization::Deref(_, mc::Implicit(..)) |
|
||||
Categorization::Deref(_, mc::UnsafePtr(..)) |
|
||||
Categorization::StaticItem => {
|
||||
let mut err = struct_span_err!(bccx, move_from.span, E0507,
|
||||
"cannot move out of {}",
|
||||
@ -152,7 +152,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||
err
|
||||
}
|
||||
|
||||
Categorization::Interior(ref b, mc::InteriorElement(ik, _)) => {
|
||||
Categorization::Interior(ref b, mc::InteriorElement(ik)) => {
|
||||
match (&b.ty.sty, ik) {
|
||||
(&ty::TySlice(..), _) |
|
||||
(_, Kind::Index) => {
|
||||
|
@ -133,7 +133,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
|
||||
RestrictionResult::Safe
|
||||
}
|
||||
|
||||
Categorization::Deref(cmt_base, _, pk) => {
|
||||
Categorization::Deref(cmt_base, pk) => {
|
||||
match pk {
|
||||
mc::Unique => {
|
||||
// R-Deref-Send-Pointer
|
||||
|
@ -284,7 +284,7 @@ const DOWNCAST_PRINTED_OPERATOR: &'static str = " as ";
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum InteriorKind {
|
||||
InteriorField(mc::FieldName),
|
||||
InteriorElement(mc::ElementKind),
|
||||
InteriorElement,
|
||||
}
|
||||
|
||||
trait ToInteriorKind { fn cleaned(self) -> InteriorKind; }
|
||||
@ -292,7 +292,7 @@ impl ToInteriorKind for mc::InteriorKind {
|
||||
fn cleaned(self) -> InteriorKind {
|
||||
match self {
|
||||
mc::InteriorField(name) => InteriorField(name),
|
||||
mc::InteriorElement(_, elem_kind) => InteriorElement(elem_kind),
|
||||
mc::InteriorElement(_) => InteriorElement,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -426,7 +426,7 @@ pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option<Rc<LoanPath<'tcx>>> {
|
||||
Some(new_lp(LpUpvar(id)))
|
||||
}
|
||||
|
||||
Categorization::Deref(ref cmt_base, _, pk) => {
|
||||
Categorization::Deref(ref cmt_base, pk) => {
|
||||
opt_loan_path(cmt_base).map(|lp| {
|
||||
new_lp(LpExtend(lp, cmt.mutbl, LpDeref(pk)))
|
||||
})
|
||||
@ -1232,7 +1232,7 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \
|
||||
}
|
||||
}
|
||||
|
||||
LpExtend(ref lp_base, _, LpInterior(_, InteriorElement(..))) => {
|
||||
LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) => {
|
||||
self.append_autoderefd_loan_path_to_string(&lp_base, out);
|
||||
out.push_str("[..]");
|
||||
}
|
||||
@ -1318,7 +1318,7 @@ impl<'tcx> fmt::Debug for InteriorKind {
|
||||
match *self {
|
||||
InteriorField(mc::NamedField(fld)) => write!(f, "{}", fld),
|
||||
InteriorField(mc::PositionalField(i)) => write!(f, "#{}", i),
|
||||
InteriorElement(..) => write!(f, "[]"),
|
||||
InteriorElement => write!(f, "[]"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ fn loan_path_is_precise(loan_path: &LoanPath) -> bool {
|
||||
LpVar(_) | LpUpvar(_) => {
|
||||
true
|
||||
}
|
||||
LpExtend(.., LpInterior(_, InteriorKind::InteriorElement(..))) => {
|
||||
LpExtend(.., LpInterior(_, InteriorKind::InteriorElement)) => {
|
||||
// Paths involving element accesses a[i] do not refer to a unique
|
||||
// location, as there is no accurate tracking of the indices.
|
||||
//
|
||||
|
@ -286,8 +286,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
hir::ExprPath(ref qpath) => {
|
||||
let substs = cx.tables.node_id_item_substs(e.id)
|
||||
.unwrap_or_else(|| tcx.intern_substs(&[]));
|
||||
let substs = cx.tables.node_substs(e.id);
|
||||
|
||||
// Avoid applying substitutions if they're empty, that'd ICE.
|
||||
let substs = if cx.substs.is_empty() {
|
||||
|
@ -584,8 +584,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
|
||||
let kind = match def {
|
||||
Def::Const(def_id) | Def::AssociatedConst(def_id) => {
|
||||
let tcx = self.tcx.global_tcx();
|
||||
let substs = self.tables.node_id_item_substs(id)
|
||||
.unwrap_or_else(|| tcx.intern_substs(&[]));
|
||||
let substs = self.tables.node_substs(id);
|
||||
match eval::lookup_const_by_id(tcx, def_id, substs) {
|
||||
Some((def_id, _substs)) => {
|
||||
// Enter the inlined constant's tables temporarily.
|
||||
|
@ -881,30 +881,37 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
|
||||
-> bool {
|
||||
use rustc::ty::adjustment::*;
|
||||
|
||||
// Ignore non-expressions.
|
||||
let expr = if let hir_map::NodeExpr(e) = cx.tcx.hir.get(id) {
|
||||
e
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Check for overloaded autoderef method calls.
|
||||
let mut source = cx.tables.expr_ty(expr);
|
||||
for adjustment in cx.tables.expr_adjustments(expr) {
|
||||
if let Adjust::Deref(Some(deref)) = adjustment.kind {
|
||||
let (def_id, substs) = deref.method_call(cx.tcx, source);
|
||||
if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
source = adjustment.target;
|
||||
}
|
||||
|
||||
// Check for method calls and overloaded operators.
|
||||
let opt_m = cx.tables.method_map.get(&ty::MethodCall::expr(id)).cloned();
|
||||
if let Some(m) = opt_m {
|
||||
if method_call_refers_to_method(cx.tcx, method, m.def_id, m.substs, id) {
|
||||
if cx.tables.is_method_call(expr) {
|
||||
let def_id = cx.tables.type_dependent_defs[&id].def_id();
|
||||
let substs = cx.tables.node_substs(id);
|
||||
if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for overloaded autoderef method calls.
|
||||
let opt_adj = cx.tables.adjustments.get(&id).cloned();
|
||||
if let Some(Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) = opt_adj {
|
||||
for i in 0..autoderefs {
|
||||
let method_call = ty::MethodCall::autoderef(id, i as u32);
|
||||
if let Some(m) = cx.tables.method_map.get(&method_call).cloned() {
|
||||
if method_call_refers_to_method(cx.tcx, method, m.def_id, m.substs, id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for calls to methods via explicit paths (e.g. `T::method()`).
|
||||
match cx.tcx.hir.get(id) {
|
||||
hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
|
||||
match expr.node {
|
||||
hir::ExprCall(ref callee, _) => {
|
||||
let def = if let hir::ExprPath(ref qpath) = callee.node {
|
||||
cx.tables.qpath_def(qpath, callee.id)
|
||||
} else {
|
||||
@ -912,8 +919,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
|
||||
};
|
||||
match def {
|
||||
Def::Method(def_id) => {
|
||||
let substs = cx.tables.node_id_item_substs(callee.id)
|
||||
.unwrap_or_else(|| cx.tcx.intern_substs(&[]));
|
||||
let substs = cx.tables.node_substs(callee.id);
|
||||
method_call_refers_to_method(
|
||||
cx.tcx, method, def_id, substs, id)
|
||||
}
|
||||
|
@ -468,21 +468,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation {
|
||||
_ => return,
|
||||
}
|
||||
|
||||
if let Some(adjustment) = cx.tables.adjustments.get(&e.id) {
|
||||
if let adjustment::Adjust::DerefRef { autoref, .. } = adjustment.kind {
|
||||
match autoref {
|
||||
Some(adjustment::AutoBorrow::Ref(_, hir::MutImmutable)) => {
|
||||
cx.span_lint(UNUSED_ALLOCATION,
|
||||
e.span,
|
||||
"unnecessary allocation, use & instead");
|
||||
}
|
||||
Some(adjustment::AutoBorrow::Ref(_, hir::MutMutable)) => {
|
||||
cx.span_lint(UNUSED_ALLOCATION,
|
||||
e.span,
|
||||
"unnecessary allocation, use &mut instead");
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
for adj in cx.tables.expr_adjustments(e) {
|
||||
if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
|
||||
let msg = match m {
|
||||
hir::MutImmutable => "unnecessary allocation, use & instead",
|
||||
hir::MutMutable => "unnecessary allocation, use &mut instead"
|
||||
};
|
||||
cx.span_lint(UNUSED_ALLOCATION, e.span, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -201,13 +201,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
exit_block.unit()
|
||||
}
|
||||
ExprKind::Call { ty, fun, args } => {
|
||||
let diverges = match ty.sty {
|
||||
ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
|
||||
// FIXME(canndrew): This is_never should probably be an is_uninhabited
|
||||
f.output().skip_binder().is_never()
|
||||
}
|
||||
_ => false
|
||||
};
|
||||
// FIXME(canndrew): This is_never should probably be an is_uninhabited
|
||||
let diverges = expr.ty.is_never();
|
||||
let intrinsic = match ty.sty {
|
||||
ty::TyFnDef(def_id, _, ref f) if
|
||||
f.abi() == Abi::RustIntrinsic ||
|
||||
|
@ -17,9 +17,10 @@ use hair::cx::to_ref::ToRef;
|
||||
use rustc::hir::def::{Def, CtorKind};
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::ty::{self, AdtKind, VariantDef, Ty};
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
|
||||
use rustc::ty::cast::CastKind as TyCastKind;
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::hir;
|
||||
use syntax::ptr::P;
|
||||
|
||||
impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
||||
type Output = Expr<'tcx>;
|
||||
@ -31,175 +32,13 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
||||
debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
|
||||
|
||||
let mut expr = make_mirror_unadjusted(cx, self);
|
||||
let adj = cx.tables().adjustments.get(&self.id).cloned();
|
||||
|
||||
debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}",
|
||||
expr,
|
||||
adj);
|
||||
|
||||
// Now apply adjustments, if any.
|
||||
match adj.map(|adj| (adj.kind, adj.target)) {
|
||||
None => {}
|
||||
Some((ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => {
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
temp_lifetime_was_shrunk: was_shrunk,
|
||||
ty: adjusted_ty,
|
||||
span: self.span,
|
||||
kind: ExprKind::ReifyFnPointer { source: expr.to_ref() },
|
||||
};
|
||||
}
|
||||
Some((ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => {
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
temp_lifetime_was_shrunk: was_shrunk,
|
||||
ty: adjusted_ty,
|
||||
span: self.span,
|
||||
kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
|
||||
};
|
||||
}
|
||||
Some((ty::adjustment::Adjust::ClosureFnPointer, adjusted_ty)) => {
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
temp_lifetime_was_shrunk: was_shrunk,
|
||||
ty: adjusted_ty,
|
||||
span: self.span,
|
||||
kind: ExprKind::ClosureFnPointer { source: expr.to_ref() },
|
||||
};
|
||||
}
|
||||
Some((ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => {
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
temp_lifetime_was_shrunk: was_shrunk,
|
||||
ty: adjusted_ty,
|
||||
span: self.span,
|
||||
kind: ExprKind::NeverToAny { source: expr.to_ref() },
|
||||
};
|
||||
}
|
||||
Some((ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => {
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
temp_lifetime_was_shrunk: was_shrunk,
|
||||
ty: adjusted_ty,
|
||||
span: self.span,
|
||||
kind: ExprKind::Cast { source: expr.to_ref() },
|
||||
};
|
||||
}
|
||||
Some((ty::adjustment::Adjust::DerefRef { autoderefs, autoref, unsize },
|
||||
adjusted_ty)) => {
|
||||
for i in 0..autoderefs {
|
||||
let i = i as u32;
|
||||
let adjusted_ty =
|
||||
expr.ty.adjust_for_autoderef(cx.tcx, self.id, self.span, i, |mc| {
|
||||
cx.tables().method_map.get(&mc).map(|m| m.ty)
|
||||
});
|
||||
debug!("make_mirror: autoderef #{}, adjusted_ty={:?}",
|
||||
i,
|
||||
adjusted_ty);
|
||||
let method_key = ty::MethodCall::autoderef(self.id, i);
|
||||
let meth_ty = cx.tables().method_map.get(&method_key).map(|m| m.ty);
|
||||
let kind = if let Some(meth_ty) = meth_ty {
|
||||
debug!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty);
|
||||
|
||||
let ref_ty = cx.tcx.no_late_bound_regions(&meth_ty.fn_ret());
|
||||
let (region, mutbl) = match ref_ty {
|
||||
Some(&ty::TyS { sty: ty::TyRef(region, mt), .. }) => (region, mt.mutbl),
|
||||
_ => span_bug!(expr.span, "autoderef returned bad type"),
|
||||
};
|
||||
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
temp_lifetime_was_shrunk: was_shrunk,
|
||||
ty: cx.tcx.mk_ref(region,
|
||||
ty::TypeAndMut {
|
||||
ty: expr.ty,
|
||||
mutbl: mutbl,
|
||||
}),
|
||||
span: expr.span,
|
||||
kind: ExprKind::Borrow {
|
||||
region: region,
|
||||
borrow_kind: to_borrow_kind(mutbl),
|
||||
arg: expr.to_ref(),
|
||||
},
|
||||
};
|
||||
|
||||
overloaded_lvalue(cx,
|
||||
self,
|
||||
method_key,
|
||||
PassArgs::ByRef,
|
||||
expr.to_ref(),
|
||||
vec![])
|
||||
} else {
|
||||
debug!("make_mirror: built-in autoderef");
|
||||
ExprKind::Deref { arg: expr.to_ref() }
|
||||
};
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
temp_lifetime_was_shrunk: was_shrunk,
|
||||
ty: adjusted_ty,
|
||||
span: self.span,
|
||||
kind: kind,
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(autoref) = autoref {
|
||||
let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref));
|
||||
match autoref {
|
||||
ty::adjustment::AutoBorrow::Ref(r, m) => {
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
temp_lifetime_was_shrunk: was_shrunk,
|
||||
ty: adjusted_ty,
|
||||
span: self.span,
|
||||
kind: ExprKind::Borrow {
|
||||
region: r,
|
||||
borrow_kind: to_borrow_kind(m),
|
||||
arg: expr.to_ref(),
|
||||
},
|
||||
};
|
||||
}
|
||||
ty::adjustment::AutoBorrow::RawPtr(m) => {
|
||||
// Convert this to a suitable `&foo` and
|
||||
// then an unsafe coercion. Limit the region to be just this
|
||||
// expression.
|
||||
let region = ty::ReScope(expr_extent);
|
||||
let region = cx.tcx.mk_region(region);
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
temp_lifetime_was_shrunk: was_shrunk,
|
||||
ty: cx.tcx.mk_ref(region,
|
||||
ty::TypeAndMut {
|
||||
ty: expr.ty,
|
||||
mutbl: m,
|
||||
}),
|
||||
span: self.span,
|
||||
kind: ExprKind::Borrow {
|
||||
region: region,
|
||||
borrow_kind: to_borrow_kind(m),
|
||||
arg: expr.to_ref(),
|
||||
},
|
||||
};
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
temp_lifetime_was_shrunk: was_shrunk,
|
||||
ty: adjusted_ty,
|
||||
span: self.span,
|
||||
kind: ExprKind::Cast { source: expr.to_ref() },
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if unsize {
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
temp_lifetime_was_shrunk: was_shrunk,
|
||||
ty: adjusted_ty,
|
||||
span: self.span,
|
||||
kind: ExprKind::Unsize { source: expr.to_ref() },
|
||||
};
|
||||
}
|
||||
}
|
||||
for adjustment in cx.tables().expr_adjustments(self) {
|
||||
debug!("make_mirror: expr={:?} applying adjustment={:?}",
|
||||
expr,
|
||||
adjustment);
|
||||
expr = apply_adjustment(cx, self, expr, adjustment);
|
||||
}
|
||||
|
||||
// Next, wrap this up in the expr's scope.
|
||||
@ -233,6 +72,96 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
hir_expr: &'tcx hir::Expr,
|
||||
mut expr: Expr<'tcx>,
|
||||
adjustment: &Adjustment<'tcx>)
|
||||
-> Expr<'tcx> {
|
||||
let Expr { temp_lifetime, temp_lifetime_was_shrunk, span, .. } = expr;
|
||||
let kind = match adjustment.kind {
|
||||
Adjust::ReifyFnPointer => {
|
||||
ExprKind::ReifyFnPointer { source: expr.to_ref() }
|
||||
}
|
||||
Adjust::UnsafeFnPointer => {
|
||||
ExprKind::UnsafeFnPointer { source: expr.to_ref() }
|
||||
}
|
||||
Adjust::ClosureFnPointer => {
|
||||
ExprKind::ClosureFnPointer { source: expr.to_ref() }
|
||||
}
|
||||
Adjust::NeverToAny => {
|
||||
ExprKind::NeverToAny { source: expr.to_ref() }
|
||||
}
|
||||
Adjust::MutToConstPointer => {
|
||||
ExprKind::Cast { source: expr.to_ref() }
|
||||
}
|
||||
Adjust::Deref(None) => {
|
||||
ExprKind::Deref { arg: expr.to_ref() }
|
||||
}
|
||||
Adjust::Deref(Some(deref)) => {
|
||||
let call = deref.method_call(cx.tcx, expr.ty);
|
||||
|
||||
expr = Expr {
|
||||
temp_lifetime,
|
||||
temp_lifetime_was_shrunk,
|
||||
ty: cx.tcx.mk_ref(deref.region,
|
||||
ty::TypeAndMut {
|
||||
ty: expr.ty,
|
||||
mutbl: deref.mutbl,
|
||||
}),
|
||||
span,
|
||||
kind: ExprKind::Borrow {
|
||||
region: deref.region,
|
||||
borrow_kind: to_borrow_kind(deref.mutbl),
|
||||
arg: expr.to_ref(),
|
||||
},
|
||||
};
|
||||
|
||||
overloaded_lvalue(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()])
|
||||
}
|
||||
Adjust::Borrow(AutoBorrow::Ref(r, m)) => {
|
||||
ExprKind::Borrow {
|
||||
region: r,
|
||||
borrow_kind: to_borrow_kind(m),
|
||||
arg: expr.to_ref(),
|
||||
}
|
||||
}
|
||||
Adjust::Borrow(AutoBorrow::RawPtr(m)) => {
|
||||
// Convert this to a suitable `&foo` and
|
||||
// then an unsafe coercion. Limit the region to be just this
|
||||
// expression.
|
||||
let region = ty::ReScope(CodeExtent::Misc(hir_expr.id));
|
||||
let region = cx.tcx.mk_region(region);
|
||||
expr = Expr {
|
||||
temp_lifetime,
|
||||
temp_lifetime_was_shrunk,
|
||||
ty: cx.tcx.mk_ref(region,
|
||||
ty::TypeAndMut {
|
||||
ty: expr.ty,
|
||||
mutbl: m,
|
||||
}),
|
||||
span,
|
||||
kind: ExprKind::Borrow {
|
||||
region: region,
|
||||
borrow_kind: to_borrow_kind(m),
|
||||
arg: expr.to_ref(),
|
||||
},
|
||||
};
|
||||
ExprKind::Cast { source: expr.to_ref() }
|
||||
}
|
||||
Adjust::Unsize => {
|
||||
ExprKind::Unsize { source: expr.to_ref() }
|
||||
}
|
||||
};
|
||||
|
||||
Expr {
|
||||
temp_lifetime,
|
||||
temp_lifetime_was_shrunk,
|
||||
ty: adjustment.target,
|
||||
span,
|
||||
kind,
|
||||
}
|
||||
}
|
||||
|
||||
fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
expr: &'tcx hir::Expr)
|
||||
-> Expr<'tcx> {
|
||||
@ -243,7 +172,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
// Here comes the interesting stuff:
|
||||
hir::ExprMethodCall(.., ref args) => {
|
||||
// Rewrite a.b(c) into UFCS form like Trait::b(a, c)
|
||||
let expr = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
|
||||
let expr = method_callee(cx, expr, None);
|
||||
let args = args.iter()
|
||||
.map(|e| e.to_ref())
|
||||
.collect();
|
||||
@ -255,7 +184,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
}
|
||||
|
||||
hir::ExprCall(ref fun, ref args) => {
|
||||
if cx.tables().is_method_call(expr.id) {
|
||||
if cx.tables().is_method_call(expr) {
|
||||
// The callee is something implementing Fn, FnMut, or FnOnce.
|
||||
// Find the actual method implementation being called and
|
||||
// build the appropriate UFCS call expression with the
|
||||
@ -263,18 +192,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
|
||||
// rewrite f(u, v) into FnOnce::call_once(f, (u, v))
|
||||
|
||||
let method = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
|
||||
|
||||
let sig = method.ty.fn_sig();
|
||||
|
||||
let sig = cx.tcx
|
||||
.no_late_bound_regions(&sig)
|
||||
.unwrap_or_else(|| span_bug!(expr.span, "method call has late-bound regions"));
|
||||
|
||||
assert_eq!(sig.inputs().len(), 2);
|
||||
let method = method_callee(cx, expr, None);
|
||||
|
||||
let arg_tys = args.iter().map(|e| cx.tables().expr_ty_adjusted(e));
|
||||
let tupled_args = Expr {
|
||||
ty: sig.inputs()[1],
|
||||
ty: cx.tcx.mk_tup(arg_tys, false),
|
||||
temp_lifetime: temp_lifetime,
|
||||
temp_lifetime_was_shrunk: was_shrunk,
|
||||
span: expr.span,
|
||||
@ -302,8 +224,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
None
|
||||
};
|
||||
if let Some((adt_def, index)) = adt_data {
|
||||
let substs = cx.tables().node_id_item_substs(fun.id)
|
||||
.unwrap_or_else(|| cx.tcx.intern_substs(&[]));
|
||||
let substs = cx.tables().node_substs(fun.id);
|
||||
let field_refs = args.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, e)| {
|
||||
@ -352,18 +273,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
}
|
||||
|
||||
hir::ExprAssignOp(op, ref lhs, ref rhs) => {
|
||||
if cx.tables().is_method_call(expr.id) {
|
||||
let pass_args = if op.node.is_by_value() {
|
||||
PassArgs::ByValue
|
||||
} else {
|
||||
PassArgs::ByRef
|
||||
};
|
||||
overloaded_operator(cx,
|
||||
expr,
|
||||
ty::MethodCall::expr(expr.id),
|
||||
pass_args,
|
||||
lhs.to_ref(),
|
||||
vec![rhs])
|
||||
if cx.tables().is_method_call(expr) {
|
||||
overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()])
|
||||
} else {
|
||||
ExprKind::AssignOp {
|
||||
op: bin_op(op.node),
|
||||
@ -376,18 +287,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) },
|
||||
|
||||
hir::ExprBinary(op, ref lhs, ref rhs) => {
|
||||
if cx.tables().is_method_call(expr.id) {
|
||||
let pass_args = if op.node.is_by_value() {
|
||||
PassArgs::ByValue
|
||||
} else {
|
||||
PassArgs::ByRef
|
||||
};
|
||||
overloaded_operator(cx,
|
||||
expr,
|
||||
ty::MethodCall::expr(expr.id),
|
||||
pass_args,
|
||||
lhs.to_ref(),
|
||||
vec![rhs])
|
||||
if cx.tables().is_method_call(expr) {
|
||||
overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()])
|
||||
} else {
|
||||
// FIXME overflow
|
||||
match (op.node, cx.constness) {
|
||||
@ -436,13 +337,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
}
|
||||
|
||||
hir::ExprIndex(ref lhs, ref index) => {
|
||||
if cx.tables().is_method_call(expr.id) {
|
||||
overloaded_lvalue(cx,
|
||||
expr,
|
||||
ty::MethodCall::expr(expr.id),
|
||||
PassArgs::ByValue,
|
||||
lhs.to_ref(),
|
||||
vec![index])
|
||||
if cx.tables().is_method_call(expr) {
|
||||
overloaded_lvalue(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()])
|
||||
} else {
|
||||
ExprKind::Index {
|
||||
lhs: lhs.to_ref(),
|
||||
@ -452,26 +348,16 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
}
|
||||
|
||||
hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => {
|
||||
if cx.tables().is_method_call(expr.id) {
|
||||
overloaded_lvalue(cx,
|
||||
expr,
|
||||
ty::MethodCall::expr(expr.id),
|
||||
PassArgs::ByValue,
|
||||
arg.to_ref(),
|
||||
vec![])
|
||||
if cx.tables().is_method_call(expr) {
|
||||
overloaded_lvalue(cx, expr, expr_ty, None, vec![arg.to_ref()])
|
||||
} else {
|
||||
ExprKind::Deref { arg: arg.to_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
hir::ExprUnary(hir::UnOp::UnNot, ref arg) => {
|
||||
if cx.tables().is_method_call(expr.id) {
|
||||
overloaded_operator(cx,
|
||||
expr,
|
||||
ty::MethodCall::expr(expr.id),
|
||||
PassArgs::ByValue,
|
||||
arg.to_ref(),
|
||||
vec![])
|
||||
if cx.tables().is_method_call(expr) {
|
||||
overloaded_operator(cx, expr, vec![arg.to_ref()])
|
||||
} else {
|
||||
ExprKind::Unary {
|
||||
op: UnOp::Not,
|
||||
@ -481,13 +367,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
}
|
||||
|
||||
hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
|
||||
if cx.tables().is_method_call(expr.id) {
|
||||
overloaded_operator(cx,
|
||||
expr,
|
||||
ty::MethodCall::expr(expr.id),
|
||||
PassArgs::ByValue,
|
||||
arg.to_ref(),
|
||||
vec![])
|
||||
if cx.tables().is_method_call(expr) {
|
||||
overloaded_operator(cx, expr, vec![arg.to_ref()])
|
||||
} else {
|
||||
// FIXME runtime-overflow
|
||||
if let hir::ExprLit(_) = arg.node {
|
||||
@ -703,18 +584,21 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
|
||||
fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
expr: &hir::Expr,
|
||||
method_call: ty::MethodCall)
|
||||
custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>)
|
||||
-> Expr<'tcx> {
|
||||
let callee = cx.tables().method_map[&method_call];
|
||||
let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
|
||||
let (def_id, substs) = custom_callee.unwrap_or_else(|| {
|
||||
(cx.tables().type_dependent_defs[&expr.id].def_id(),
|
||||
cx.tables().node_substs(expr.id))
|
||||
});
|
||||
Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
temp_lifetime_was_shrunk: was_shrunk,
|
||||
ty: callee.ty,
|
||||
ty: cx.tcx.type_of(def_id).subst(cx.tcx, substs),
|
||||
span: expr.span,
|
||||
kind: ExprKind::Literal {
|
||||
literal: Literal::Value {
|
||||
value: ConstVal::Function(callee.def_id, callee.substs),
|
||||
value: ConstVal::Function(def_id, substs),
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -739,8 +623,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
expr: &'tcx hir::Expr,
|
||||
def: Def)
|
||||
-> ExprKind<'tcx> {
|
||||
let substs = cx.tables().node_id_item_substs(expr.id)
|
||||
.unwrap_or_else(|| cx.tcx.intern_substs(&[]));
|
||||
let substs = cx.tables().node_substs(expr.id);
|
||||
match def {
|
||||
// A regular function, constructor function or a constant.
|
||||
Def::Fn(def_id) |
|
||||
@ -941,90 +824,59 @@ fn bin_op(op: hir::BinOp_) -> BinOp {
|
||||
}
|
||||
}
|
||||
|
||||
enum PassArgs {
|
||||
ByValue,
|
||||
ByRef,
|
||||
}
|
||||
|
||||
fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
expr: &'tcx hir::Expr,
|
||||
method_call: ty::MethodCall,
|
||||
pass_args: PassArgs,
|
||||
receiver: ExprRef<'tcx>,
|
||||
args: Vec<&'tcx P<hir::Expr>>)
|
||||
args: Vec<ExprRef<'tcx>>)
|
||||
-> ExprKind<'tcx> {
|
||||
// the receiver has all the adjustments that are needed, so we can
|
||||
// just push a reference to it
|
||||
let mut argrefs = vec![receiver];
|
||||
|
||||
// the arguments, unfortunately, do not, so if this is a ByRef
|
||||
// operator, we have to gin up the autorefs (but by value is easy)
|
||||
match pass_args {
|
||||
PassArgs::ByValue => argrefs.extend(args.iter().map(|arg| arg.to_ref())),
|
||||
|
||||
PassArgs::ByRef => {
|
||||
let region = cx.tcx.node_scope_region(expr.id);
|
||||
let (temp_lifetime, was_shrunk) =
|
||||
cx.region_maps.temporary_scope2(expr.id);
|
||||
argrefs.extend(args.iter()
|
||||
.map(|arg| {
|
||||
let arg_ty = cx.tables().expr_ty_adjusted(arg);
|
||||
let adjusted_ty = cx.tcx.mk_ref(region,
|
||||
ty::TypeAndMut {
|
||||
ty: arg_ty,
|
||||
mutbl: hir::MutImmutable,
|
||||
});
|
||||
Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
temp_lifetime_was_shrunk: was_shrunk,
|
||||
ty: adjusted_ty,
|
||||
span: expr.span,
|
||||
kind: ExprKind::Borrow {
|
||||
region: region,
|
||||
borrow_kind: BorrowKind::Shared,
|
||||
arg: arg.to_ref(),
|
||||
},
|
||||
}
|
||||
.to_ref()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
// now create the call itself
|
||||
let fun = method_callee(cx, expr, method_call);
|
||||
let fun = method_callee(cx, expr, None);
|
||||
ExprKind::Call {
|
||||
ty: fun.ty,
|
||||
fun: fun.to_ref(),
|
||||
args: argrefs,
|
||||
args,
|
||||
}
|
||||
}
|
||||
|
||||
fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
expr: &'tcx hir::Expr,
|
||||
method_call: ty::MethodCall,
|
||||
pass_args: PassArgs,
|
||||
receiver: ExprRef<'tcx>,
|
||||
args: Vec<&'tcx P<hir::Expr>>)
|
||||
lvalue_ty: Ty<'tcx>,
|
||||
custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>,
|
||||
args: Vec<ExprRef<'tcx>>)
|
||||
-> ExprKind<'tcx> {
|
||||
// For an overloaded *x or x[y] expression of type T, the method
|
||||
// call returns an &T and we must add the deref so that the types
|
||||
// line up (this is because `*x` and `x[y]` represent lvalues):
|
||||
|
||||
// to find the type &T of the content returned by the method;
|
||||
let ref_ty = cx.tables().method_map[&method_call].ty.fn_ret();
|
||||
let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap();
|
||||
// callees always have all late-bound regions fully instantiated,
|
||||
let recv_ty = match args[0] {
|
||||
ExprRef::Hair(e) => cx.tables().expr_ty_adjusted(e),
|
||||
ExprRef::Mirror(ref e) => e.ty
|
||||
};
|
||||
|
||||
// Reconstruct the output assuming it's a reference with the
|
||||
// same region and mutability as the receiver. This holds for
|
||||
// `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
|
||||
let (region, mt) = match recv_ty.sty {
|
||||
ty::TyRef(region, mt) => (region, mt),
|
||||
_ => span_bug!(expr.span, "overloaded_lvalue: receiver is not a reference"),
|
||||
};
|
||||
let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut {
|
||||
ty: lvalue_ty,
|
||||
mutbl: mt.mutbl,
|
||||
});
|
||||
|
||||
// construct the complete expression `foo()` for the overloaded call,
|
||||
// which will yield the &T type
|
||||
let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
|
||||
let ref_kind = overloaded_operator(cx, expr, method_call, pass_args, receiver, args);
|
||||
let fun = method_callee(cx, expr, custom_callee);
|
||||
let ref_expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
temp_lifetime_was_shrunk: was_shrunk,
|
||||
ty: ref_ty,
|
||||
span: expr.span,
|
||||
kind: ref_kind,
|
||||
kind: ExprKind::Call {
|
||||
ty: fun.ty,
|
||||
fun: fun.to_ref(),
|
||||
args,
|
||||
},
|
||||
};
|
||||
|
||||
// construct and return a deref wrapper `*foo()`
|
||||
|
@ -280,11 +280,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let method_call = ty::MethodCall::expr(e.id);
|
||||
match e.node {
|
||||
hir::ExprUnary(..) |
|
||||
hir::ExprBinary(..) |
|
||||
hir::ExprIndex(..) if v.tables.method_map.contains_key(&method_call) => {
|
||||
hir::ExprIndex(..) if v.tables.is_method_call(e) => {
|
||||
v.promotable = false;
|
||||
}
|
||||
hir::ExprBox(_) => {
|
||||
@ -381,9 +380,9 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
|
||||
}
|
||||
}
|
||||
hir::ExprMethodCall(..) => {
|
||||
let method = v.tables.method_map[&method_call];
|
||||
match v.tcx.associated_item(method.def_id).container {
|
||||
ty::ImplContainer(_) => v.handle_const_fn_call(method.def_id, node_ty),
|
||||
let def_id = v.tables.type_dependent_defs[&e.id].def_id();
|
||||
match v.tcx.associated_item(def_id).container {
|
||||
ty::ImplContainer(_) => v.handle_const_fn_call(def_id, node_ty),
|
||||
ty::TraitContainer(_) => v.promotable = false
|
||||
}
|
||||
}
|
||||
@ -442,18 +441,21 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
|
||||
fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) {
|
||||
use rustc::ty::adjustment::*;
|
||||
|
||||
match v.tables.adjustments.get(&e.id).map(|adj| adj.kind) {
|
||||
None |
|
||||
Some(Adjust::NeverToAny) |
|
||||
Some(Adjust::ReifyFnPointer) |
|
||||
Some(Adjust::UnsafeFnPointer) |
|
||||
Some(Adjust::ClosureFnPointer) |
|
||||
Some(Adjust::MutToConstPointer) => {}
|
||||
for adjustment in v.tables.expr_adjustments(e) {
|
||||
match adjustment.kind {
|
||||
Adjust::NeverToAny |
|
||||
Adjust::ReifyFnPointer |
|
||||
Adjust::UnsafeFnPointer |
|
||||
Adjust::ClosureFnPointer |
|
||||
Adjust::MutToConstPointer |
|
||||
Adjust::Borrow(_) |
|
||||
Adjust::Unsize => {}
|
||||
|
||||
Some(Adjust::DerefRef { autoderefs, .. }) => {
|
||||
if (0..autoderefs as u32)
|
||||
.any(|autoderef| v.tables.is_overloaded_autoderef(e.id, autoderef)) {
|
||||
v.promotable = false;
|
||||
Adjust::Deref(ref overloaded) => {
|
||||
if overloaded.is_some() {
|
||||
v.promotable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -512,7 +514,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
|
||||
Categorization::StaticItem => {
|
||||
break;
|
||||
}
|
||||
Categorization::Deref(ref cmt, ..) |
|
||||
Categorization::Deref(ref cmt, _) |
|
||||
Categorization::Downcast(ref cmt, _) |
|
||||
Categorization::Interior(ref cmt, _) => {
|
||||
cur = cmt;
|
||||
|
@ -564,8 +564,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
||||
}
|
||||
}
|
||||
ast::ExprKind::MethodCall(..) => {
|
||||
let method_call = ty::MethodCall::expr(expr.id);
|
||||
let method_id = self.tables.method_map[&method_call].def_id;
|
||||
let method_id = self.tables.type_dependent_defs[&expr.id].def_id();
|
||||
let (def_id, decl_id) = match self.tcx.associated_item(method_id).container {
|
||||
ty::ImplContainer(_) => (Some(method_id), None),
|
||||
ty::TraitContainer(_) => (None, Some(method_id)),
|
||||
|
@ -619,7 +619,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// Type check the path.
|
||||
let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
|
||||
// Replace constructor type with constructed type for tuple struct patterns.
|
||||
let pat_ty = tcx.no_late_bound_regions(&pat_ty.fn_ret()).expect("expected fn type");
|
||||
let pat_ty = pat_ty.fn_sig().output();
|
||||
let pat_ty = tcx.no_late_bound_regions(&pat_ty).expect("expected fn type");
|
||||
self.demand_eqtype(pat.span, expected, pat_ty);
|
||||
|
||||
// Type check subpatterns.
|
||||
|
@ -11,19 +11,20 @@
|
||||
use astconv::AstConv;
|
||||
|
||||
use super::{FnCtxt, LvalueOp};
|
||||
use super::method::MethodCallee;
|
||||
|
||||
use check::coercion::AsCoercionSite;
|
||||
use rustc::infer::InferOk;
|
||||
use rustc::traits;
|
||||
use rustc::ty::{self, Ty, TraitRef};
|
||||
use rustc::ty::{ToPredicate, TypeFoldable};
|
||||
use rustc::ty::{MethodCall, MethodCallee};
|
||||
use rustc::ty::{LvaluePreference, NoPreference};
|
||||
use rustc::hir;
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
|
||||
|
||||
use syntax_pos::Span;
|
||||
use syntax::symbol::Symbol;
|
||||
|
||||
use std::iter;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum AutoderefKind {
|
||||
Builtin,
|
||||
@ -150,52 +151,59 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
|
||||
self.fcx.resolve_type_vars_if_possible(&self.cur_ty)
|
||||
}
|
||||
|
||||
pub fn finalize(self, pref: LvaluePreference, expr: &hir::Expr) {
|
||||
let fcx = self.fcx;
|
||||
fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, &[expr]));
|
||||
pub fn step_count(&self) -> usize {
|
||||
self.steps.len()
|
||||
}
|
||||
|
||||
pub fn finalize_as_infer_ok<E>(self, pref: LvaluePreference, exprs: &[E])
|
||||
-> InferOk<'tcx, ()>
|
||||
where E: AsCoercionSite
|
||||
{
|
||||
let Autoderef { fcx, span, mut obligations, steps, .. } = self;
|
||||
let methods: Vec<_> = steps
|
||||
.iter()
|
||||
.map(|&(ty, kind)| {
|
||||
if let AutoderefKind::Overloaded = kind {
|
||||
fcx.try_overloaded_deref(span, None, ty, pref)
|
||||
.map(|InferOk { value, obligations: o }| {
|
||||
obligations.extend(o);
|
||||
value
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
/// Returns the adjustment steps.
|
||||
pub fn adjust_steps(&self, pref: LvaluePreference)
|
||||
-> Vec<Adjustment<'tcx>> {
|
||||
self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(pref))
|
||||
}
|
||||
|
||||
debug!("finalize({:?}) - {:?},{:?}",
|
||||
pref,
|
||||
methods,
|
||||
obligations);
|
||||
|
||||
for expr in exprs {
|
||||
let expr = expr.as_coercion_site();
|
||||
debug!("finalize - finalizing #{} - {:?}", expr.id, expr);
|
||||
for (n, method) in methods.iter().enumerate() {
|
||||
if let &Some(method) = method {
|
||||
let method_call = MethodCall::autoderef(expr.id, n as u32);
|
||||
fcx.tables.borrow_mut().method_map.insert(method_call, method);
|
||||
}
|
||||
pub fn adjust_steps_as_infer_ok(&self, pref: LvaluePreference)
|
||||
-> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
|
||||
let mut obligations = vec![];
|
||||
let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty)
|
||||
.chain(iter::once(self.cur_ty));
|
||||
let steps: Vec<_> = self.steps.iter().map(|&(source, kind)| {
|
||||
if let AutoderefKind::Overloaded = kind {
|
||||
self.fcx.try_overloaded_deref(self.span, source, pref)
|
||||
.and_then(|InferOk { value: method, obligations: o }| {
|
||||
obligations.extend(o);
|
||||
if let ty::TyRef(region, mt) = method.sig.output().sty {
|
||||
Some(OverloadedDeref {
|
||||
region,
|
||||
mutbl: mt.mutbl,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}).zip(targets).map(|(autoderef, target)| {
|
||||
Adjustment {
|
||||
kind: Adjust::Deref(autoderef),
|
||||
target
|
||||
}
|
||||
}).collect();
|
||||
|
||||
InferOk {
|
||||
value: (),
|
||||
obligations
|
||||
obligations,
|
||||
value: steps
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finalize(self) {
|
||||
let fcx = self.fcx;
|
||||
fcx.register_predicates(self.into_obligations());
|
||||
}
|
||||
|
||||
pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||
self.obligations
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
@ -212,14 +220,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
pub fn try_overloaded_deref(&self,
|
||||
span: Span,
|
||||
base_expr: Option<&hir::Expr>,
|
||||
base_ty: Ty<'tcx>,
|
||||
pref: LvaluePreference)
|
||||
-> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
|
||||
let rcvr = base_expr.map(|base_expr| super::AdjustedRcvr {
|
||||
rcvr_expr: base_expr, autoderefs: 0, unsize: false
|
||||
});
|
||||
|
||||
self.try_overloaded_lvalue_op(span, rcvr, base_ty, &[], pref, LvalueOp::Deref)
|
||||
self.try_overloaded_lvalue_op(span, base_ty, &[], pref, LvalueOp::Deref)
|
||||
}
|
||||
}
|
||||
|
@ -8,13 +8,16 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use super::{DeferredCallResolution, Expectation, FnCtxt, TupleArgumentsFlag};
|
||||
use super::{Expectation, FnCtxt, TupleArgumentsFlag};
|
||||
use super::autoderef::Autoderef;
|
||||
use super::method::MethodCallee;
|
||||
|
||||
use hir::def::Def;
|
||||
use hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc::{infer, traits};
|
||||
use rustc::ty::{self, TyCtxt, LvaluePreference, Ty};
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
|
||||
use syntax::abi;
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax_pos::Span;
|
||||
@ -33,9 +36,9 @@ pub fn check_legal_trait_for_method_call(tcx: TyCtxt, span: Span, trait_id: DefI
|
||||
}
|
||||
|
||||
enum CallStep<'tcx> {
|
||||
Builtin,
|
||||
Builtin(Ty<'tcx>),
|
||||
DeferredClosure(ty::FnSig<'tcx>),
|
||||
Overloaded(ty::MethodCallee<'tcx>),
|
||||
Overloaded(MethodCallee<'tcx>),
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
@ -49,13 +52,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty);
|
||||
|
||||
let mut autoderef = self.autoderef(callee_expr.span, expr_ty);
|
||||
let result = autoderef.by_ref()
|
||||
.flat_map(|(adj_ty, idx)| {
|
||||
self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx)
|
||||
})
|
||||
.next();
|
||||
let callee_ty = autoderef.unambiguous_final_ty();
|
||||
autoderef.finalize(LvaluePreference::NoPreference, callee_expr);
|
||||
let mut result = None;
|
||||
while result.is_none() && autoderef.next().is_some() {
|
||||
result = self.try_overloaded_call_step(call_expr, callee_expr, &autoderef);
|
||||
}
|
||||
autoderef.finalize();
|
||||
|
||||
let output = match result {
|
||||
None => {
|
||||
@ -63,7 +64,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected)
|
||||
}
|
||||
|
||||
Some(CallStep::Builtin) => {
|
||||
Some(CallStep::Builtin(callee_ty)) => {
|
||||
self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected)
|
||||
}
|
||||
|
||||
@ -72,11 +73,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
Some(CallStep::Overloaded(method_callee)) => {
|
||||
self.confirm_overloaded_call(call_expr,
|
||||
callee_expr,
|
||||
arg_exprs,
|
||||
expected,
|
||||
method_callee)
|
||||
self.confirm_overloaded_call(call_expr, arg_exprs, expected, method_callee)
|
||||
}
|
||||
};
|
||||
|
||||
@ -89,19 +86,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
fn try_overloaded_call_step(&self,
|
||||
call_expr: &'gcx hir::Expr,
|
||||
callee_expr: &'gcx hir::Expr,
|
||||
adjusted_ty: Ty<'tcx>,
|
||||
autoderefs: usize)
|
||||
autoderef: &Autoderef<'a, 'gcx, 'tcx>)
|
||||
-> Option<CallStep<'tcx>> {
|
||||
debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})",
|
||||
let adjusted_ty = autoderef.unambiguous_final_ty();
|
||||
debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})",
|
||||
call_expr,
|
||||
adjusted_ty,
|
||||
autoderefs);
|
||||
adjusted_ty);
|
||||
|
||||
// If the callee is a bare function or a closure, then we're all set.
|
||||
match self.structurally_resolved_type(callee_expr.span, adjusted_ty).sty {
|
||||
match adjusted_ty.sty {
|
||||
ty::TyFnDef(..) | ty::TyFnPtr(_) => {
|
||||
self.apply_autoderef_adjustment(callee_expr.id, autoderefs, adjusted_ty);
|
||||
return Some(CallStep::Builtin);
|
||||
let adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference);
|
||||
self.apply_adjustments(callee_expr, adjustments);
|
||||
return Some(CallStep::Builtin(adjusted_ty));
|
||||
}
|
||||
|
||||
ty::TyClosure(def_id, substs) => {
|
||||
@ -116,15 +113,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
infer::FnCall,
|
||||
&closure_ty)
|
||||
.0;
|
||||
self.record_deferred_call_resolution(def_id,
|
||||
Box::new(CallResolution {
|
||||
call_expr: call_expr,
|
||||
callee_expr: callee_expr,
|
||||
adjusted_ty: adjusted_ty,
|
||||
autoderefs: autoderefs,
|
||||
fn_sig: fn_sig.clone(),
|
||||
closure_def_id: def_id,
|
||||
}));
|
||||
let adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference);
|
||||
self.record_deferred_call_resolution(def_id, DeferredCallResolution {
|
||||
call_expr,
|
||||
callee_expr,
|
||||
adjusted_ty,
|
||||
adjustments,
|
||||
fn_sig,
|
||||
closure_def_id: def_id,
|
||||
});
|
||||
return Some(CallStep::DeferredClosure(fn_sig));
|
||||
}
|
||||
}
|
||||
@ -137,47 +134,54 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// over the top. The simplest fix by far is to just ignore
|
||||
// this case and deref again, so we wind up with
|
||||
// `FnMut::call_mut(&mut *x, ())`.
|
||||
ty::TyRef(..) if autoderefs == 0 => {
|
||||
ty::TyRef(..) if autoderef.step_count() == 0 => {
|
||||
return None;
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.try_overloaded_call_traits(call_expr, callee_expr, adjusted_ty, autoderefs)
|
||||
.map(|method_callee| CallStep::Overloaded(method_callee))
|
||||
self.try_overloaded_call_traits(call_expr, adjusted_ty).map(|(autoref, method)| {
|
||||
let mut adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference);
|
||||
adjustments.extend(autoref);
|
||||
self.apply_adjustments(callee_expr, adjustments);
|
||||
CallStep::Overloaded(method)
|
||||
})
|
||||
}
|
||||
|
||||
fn try_overloaded_call_traits(&self,
|
||||
call_expr: &hir::Expr,
|
||||
callee_expr: &hir::Expr,
|
||||
adjusted_ty: Ty<'tcx>,
|
||||
autoderefs: usize)
|
||||
-> Option<ty::MethodCallee<'tcx>> {
|
||||
adjusted_ty: Ty<'tcx>)
|
||||
-> Option<(Option<Adjustment<'tcx>>,
|
||||
MethodCallee<'tcx>)> {
|
||||
// Try the options that are least restrictive on the caller first.
|
||||
for &(opt_trait_def_id, method_name) in
|
||||
&[(self.tcx.lang_items.fn_trait(), Symbol::intern("call")),
|
||||
(self.tcx.lang_items.fn_mut_trait(), Symbol::intern("call_mut")),
|
||||
(self.tcx.lang_items.fn_once_trait(), Symbol::intern("call_once"))] {
|
||||
for &(opt_trait_def_id, method_name, borrow) in
|
||||
&[(self.tcx.lang_items.fn_trait(), Symbol::intern("call"), true),
|
||||
(self.tcx.lang_items.fn_mut_trait(), Symbol::intern("call_mut"), true),
|
||||
(self.tcx.lang_items.fn_once_trait(), Symbol::intern("call_once"), false)] {
|
||||
let trait_def_id = match opt_trait_def_id {
|
||||
Some(def_id) => def_id,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
match self.lookup_method_in_trait_adjusted(call_expr.span,
|
||||
Some(super::AdjustedRcvr {
|
||||
rcvr_expr: callee_expr,
|
||||
autoderefs,
|
||||
unsize: false
|
||||
}),
|
||||
method_name,
|
||||
trait_def_id,
|
||||
adjusted_ty,
|
||||
None) {
|
||||
match self.lookup_method_in_trait(call_expr.span,
|
||||
method_name,
|
||||
trait_def_id,
|
||||
adjusted_ty,
|
||||
None) {
|
||||
None => continue,
|
||||
Some(ok) => {
|
||||
let method_callee = self.register_infer_ok_obligations(ok);
|
||||
return Some(method_callee);
|
||||
let method = self.register_infer_ok_obligations(ok);
|
||||
let mut autoref = None;
|
||||
if borrow {
|
||||
if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
|
||||
autoref = Some(Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
|
||||
target: method.sig.inputs()[0]
|
||||
});
|
||||
}
|
||||
}
|
||||
return Some((autoref, method));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -301,42 +305,33 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
fn confirm_overloaded_call(&self,
|
||||
call_expr: &hir::Expr,
|
||||
callee_expr: &'gcx hir::Expr,
|
||||
arg_exprs: &'gcx [hir::Expr],
|
||||
expected: Expectation<'tcx>,
|
||||
method_callee: ty::MethodCallee<'tcx>)
|
||||
method_callee: MethodCallee<'tcx>)
|
||||
-> Ty<'tcx> {
|
||||
let output_type = self.check_method_argument_types(call_expr.span,
|
||||
method_callee.ty,
|
||||
callee_expr,
|
||||
Ok(method_callee),
|
||||
arg_exprs,
|
||||
TupleArgumentsFlag::TupleArguments,
|
||||
expected);
|
||||
|
||||
self.write_overloaded_call_method_map(call_expr, method_callee);
|
||||
self.write_method_call(call_expr.id, method_callee);
|
||||
output_type
|
||||
}
|
||||
|
||||
fn write_overloaded_call_method_map(&self,
|
||||
call_expr: &hir::Expr,
|
||||
method_callee: ty::MethodCallee<'tcx>) {
|
||||
let method_call = ty::MethodCall::expr(call_expr.id);
|
||||
self.tables.borrow_mut().method_map.insert(method_call, method_callee);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CallResolution<'gcx: 'tcx, 'tcx> {
|
||||
pub struct DeferredCallResolution<'gcx: 'tcx, 'tcx> {
|
||||
call_expr: &'gcx hir::Expr,
|
||||
callee_expr: &'gcx hir::Expr,
|
||||
adjusted_ty: Ty<'tcx>,
|
||||
autoderefs: usize,
|
||||
adjustments: Vec<Adjustment<'tcx>>,
|
||||
fn_sig: ty::FnSig<'tcx>,
|
||||
closure_def_id: DefId,
|
||||
}
|
||||
|
||||
impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tcx> {
|
||||
fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
|
||||
impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> {
|
||||
pub fn resolve(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
|
||||
debug!("DeferredCallResolution::resolve() {:?}", self);
|
||||
|
||||
// we should not be invoked until the closure kind has been
|
||||
@ -345,10 +340,8 @@ impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tc
|
||||
|
||||
// We may now know enough to figure out fn vs fnmut etc.
|
||||
match fcx.try_overloaded_call_traits(self.call_expr,
|
||||
self.callee_expr,
|
||||
self.adjusted_ty,
|
||||
self.autoderefs) {
|
||||
Some(method_callee) => {
|
||||
self.adjusted_ty) {
|
||||
Some((autoref, method_callee)) => {
|
||||
// One problem is that when we get here, we are going
|
||||
// to have a newly instantiated function signature
|
||||
// from the call trait. This has to be reconciled with
|
||||
@ -357,9 +350,7 @@ impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tc
|
||||
// can't because of the annoying need for a TypeTrace.
|
||||
// (This always bites me, should find a way to
|
||||
// refactor it.)
|
||||
let method_sig = fcx.tcx
|
||||
.no_late_bound_regions(&method_callee.ty.fn_sig())
|
||||
.unwrap();
|
||||
let method_sig = method_callee.sig;
|
||||
|
||||
debug!("attempt_resolution: method_callee={:?}", method_callee);
|
||||
|
||||
@ -370,7 +361,11 @@ impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tc
|
||||
|
||||
fcx.demand_eqtype(self.call_expr.span, method_sig.output(), self.fn_sig.output());
|
||||
|
||||
fcx.write_overloaded_call_method_map(self.call_expr, method_callee);
|
||||
let mut adjustments = self.adjustments;
|
||||
adjustments.extend(autoref);
|
||||
fcx.apply_adjustments(self.callee_expr, adjustments);
|
||||
|
||||
fcx.write_method_call(self.call_expr.id, method_callee);
|
||||
}
|
||||
None => {
|
||||
span_bug!(self.call_expr.span,
|
||||
|
@ -95,7 +95,7 @@ impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
type CoerceResult<'tcx> = InferResult<'tcx, Adjustment<'tcx>>;
|
||||
type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>;
|
||||
|
||||
fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
|
||||
to_mutbl: hir::Mutability)
|
||||
@ -108,23 +108,18 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
|
||||
}
|
||||
}
|
||||
|
||||
fn identity<'tcx>() -> Adjust<'tcx> {
|
||||
Adjust::DerefRef {
|
||||
autoderefs: 0,
|
||||
autoref: None,
|
||||
unsize: false,
|
||||
}
|
||||
fn identity(_: Ty) -> Vec<Adjustment> { vec![] }
|
||||
|
||||
fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>> {
|
||||
move |target| vec![Adjustment { kind, target }]
|
||||
}
|
||||
|
||||
fn success<'tcx>(kind: Adjust<'tcx>,
|
||||
fn success<'tcx>(adj: Vec<Adjustment<'tcx>>,
|
||||
target: Ty<'tcx>,
|
||||
obligations: traits::PredicateObligations<'tcx>)
|
||||
-> CoerceResult<'tcx> {
|
||||
Ok(InferOk {
|
||||
value: Adjustment {
|
||||
kind,
|
||||
target
|
||||
},
|
||||
value: (adj, target),
|
||||
obligations
|
||||
})
|
||||
}
|
||||
@ -150,26 +145,22 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
/// Unify two types (using sub or lub) and produce a specific coercion.
|
||||
fn unify_and(&self, a: Ty<'tcx>, b: Ty<'tcx>, kind: Adjust<'tcx>)
|
||||
-> CoerceResult<'tcx> {
|
||||
fn unify_and<F>(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F)
|
||||
-> CoerceResult<'tcx>
|
||||
where F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>
|
||||
{
|
||||
self.unify(&a, &b).and_then(|InferOk { value: ty, obligations }| {
|
||||
success(kind, ty, obligations)
|
||||
success(f(ty), ty, obligations)
|
||||
})
|
||||
}
|
||||
|
||||
fn coerce<E>(&self,
|
||||
exprs: &[E],
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>)
|
||||
-> CoerceResult<'tcx>
|
||||
where E: AsCoercionSite
|
||||
{
|
||||
fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
|
||||
let a = self.shallow_resolve(a);
|
||||
debug!("Coerce.tys({:?} => {:?})", a, b);
|
||||
|
||||
// Just ignore error types.
|
||||
if a.references_error() || b.references_error() {
|
||||
return success(identity(), b, vec![]);
|
||||
return success(vec![], b, vec![]);
|
||||
}
|
||||
|
||||
if a.is_never() {
|
||||
@ -186,9 +177,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
// already resolved in some way.
|
||||
let diverging_ty = self.next_diverging_ty_var(
|
||||
TypeVariableOrigin::AdjustmentType(self.cause.span));
|
||||
self.unify_and(&b, &diverging_ty, Adjust::NeverToAny)
|
||||
self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny))
|
||||
} else {
|
||||
success(Adjust::NeverToAny, b, vec![])
|
||||
success(simple(Adjust::NeverToAny)(b), b, vec![])
|
||||
};
|
||||
}
|
||||
|
||||
@ -210,7 +201,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
ty::TyRef(r_b, mt_b) => {
|
||||
return self.coerce_borrowed_pointer(exprs, a, b, r_b, mt_b);
|
||||
return self.coerce_borrowed_pointer(a, b, r_b, mt_b);
|
||||
}
|
||||
|
||||
_ => {}
|
||||
@ -237,7 +228,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
}
|
||||
_ => {
|
||||
// Otherwise, just use unification rules.
|
||||
self.unify_and(a, b, identity())
|
||||
self.unify_and(a, b, identity)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -245,15 +236,12 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
/// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
|
||||
/// To match `A` with `B`, autoderef will be performed,
|
||||
/// calling `deref`/`deref_mut` where necessary.
|
||||
fn coerce_borrowed_pointer<E>(&self,
|
||||
exprs: &[E],
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
r_b: ty::Region<'tcx>,
|
||||
mt_b: TypeAndMut<'tcx>)
|
||||
-> CoerceResult<'tcx>
|
||||
where E: AsCoercionSite
|
||||
{
|
||||
fn coerce_borrowed_pointer(&self,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
r_b: ty::Region<'tcx>,
|
||||
mt_b: TypeAndMut<'tcx>)
|
||||
-> CoerceResult<'tcx> {
|
||||
|
||||
debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b);
|
||||
|
||||
@ -268,7 +256,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
|
||||
(r_a, mt_a)
|
||||
}
|
||||
_ => return self.unify_and(a, b, identity()),
|
||||
_ => return self.unify_and(a, b, identity),
|
||||
};
|
||||
|
||||
let span = self.cause.span;
|
||||
@ -375,7 +363,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
});
|
||||
match self.unify(derefd_ty_a, b) {
|
||||
Ok(ok) => {
|
||||
found = Some((ok, autoderefs));
|
||||
found = Some(ok);
|
||||
break;
|
||||
}
|
||||
Err(err) => {
|
||||
@ -391,7 +379,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
// (e.g., in example above, the failure from relating `Vec<T>`
|
||||
// to the target type), since that should be the least
|
||||
// confusing.
|
||||
let (InferOk { value: ty, mut obligations }, autoderefs) = match found {
|
||||
let InferOk { value: ty, mut obligations } = match found {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
let err = first_error.expect("coerce_borrowed_pointer had no error");
|
||||
@ -400,7 +388,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
if ty == a && mt_a.mutbl == hir::MutImmutable && autoderefs == 1 {
|
||||
if ty == a && mt_a.mutbl == hir::MutImmutable && autoderef.step_count() == 1 {
|
||||
// As a special case, if we would produce `&'a *x`, that's
|
||||
// a total no-op. We end up with the type `&'a T` just as
|
||||
// we started with. In that case, just skip it
|
||||
@ -413,29 +401,31 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
// `self.x`, but we auto-coerce it to `foo(&mut *self.x)`,
|
||||
// which is a borrow.
|
||||
assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U
|
||||
return success(identity(), ty, obligations);
|
||||
return success(vec![], ty, obligations);
|
||||
}
|
||||
|
||||
let pref = LvaluePreference::from_mutbl(mt_b.mutbl);
|
||||
let InferOk { value: mut adjustments, obligations: o }
|
||||
= autoderef.adjust_steps_as_infer_ok(pref);
|
||||
obligations.extend(o);
|
||||
obligations.extend(autoderef.into_obligations());
|
||||
|
||||
// Now apply the autoref. We have to extract the region out of
|
||||
// the final ref type we got.
|
||||
let r_borrow = match ty.sty {
|
||||
ty::TyRef(r_borrow, _) => r_borrow,
|
||||
_ => span_bug!(span, "expected a ref type, got {:?}", ty),
|
||||
};
|
||||
let autoref = Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl));
|
||||
debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}",
|
||||
adjustments.push(Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mt_b.mutbl)),
|
||||
target: ty
|
||||
});
|
||||
|
||||
debug!("coerce_borrowed_pointer: succeeded ty={:?} adjustments={:?}",
|
||||
ty,
|
||||
autoderefs,
|
||||
autoref);
|
||||
adjustments);
|
||||
|
||||
let pref = LvaluePreference::from_mutbl(mt_b.mutbl);
|
||||
obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs).obligations);
|
||||
|
||||
success(Adjust::DerefRef {
|
||||
autoderefs: autoderefs,
|
||||
autoref: autoref,
|
||||
unsize: false,
|
||||
}, ty, obligations)
|
||||
success(adjustments, ty, obligations)
|
||||
}
|
||||
|
||||
|
||||
@ -460,27 +450,40 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
// that, at which point we will need extra checks on the target here.
|
||||
|
||||
// Handle reborrows before selecting `Source: CoerceUnsized<Target>`.
|
||||
let (source, reborrow) = match (&source.sty, &target.sty) {
|
||||
let reborrow = match (&source.sty, &target.sty) {
|
||||
(&ty::TyRef(_, mt_a), &ty::TyRef(_, mt_b)) => {
|
||||
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
|
||||
|
||||
let coercion = Coercion(self.cause.span);
|
||||
let r_borrow = self.next_region_var(coercion);
|
||||
(mt_a.ty, Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl)))
|
||||
Some((Adjustment {
|
||||
kind: Adjust::Deref(None),
|
||||
target: mt_a.ty
|
||||
}, Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mt_b.mutbl)),
|
||||
target: self.tcx.mk_ref(r_borrow, ty::TypeAndMut {
|
||||
mutbl: mt_b.mutbl,
|
||||
ty: mt_a.ty
|
||||
})
|
||||
}))
|
||||
}
|
||||
(&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => {
|
||||
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
|
||||
(mt_a.ty, Some(AutoBorrow::RawPtr(mt_b.mutbl)))
|
||||
}
|
||||
_ => (source, None),
|
||||
};
|
||||
let coerce_source = source.adjust_for_autoref(self.tcx, reborrow);
|
||||
|
||||
let adjust = Adjust::DerefRef {
|
||||
autoderefs: if reborrow.is_some() { 1 } else { 0 },
|
||||
autoref: reborrow,
|
||||
unsize: true,
|
||||
Some((Adjustment {
|
||||
kind: Adjust::Deref(None),
|
||||
target: mt_a.ty
|
||||
}, Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::RawPtr(mt_b.mutbl)),
|
||||
target: self.tcx.mk_ptr(ty::TypeAndMut {
|
||||
mutbl: mt_b.mutbl,
|
||||
ty: mt_a.ty
|
||||
})
|
||||
}))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let coerce_source = reborrow.as_ref().map_or(source, |&(_, ref r)| r.target);
|
||||
|
||||
// Setup either a subtyping or a LUB relationship between
|
||||
// the `CoerceUnsized` target type and the expected type.
|
||||
@ -488,7 +491,18 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
// for the former and let type inference do the rest.
|
||||
let origin = TypeVariableOrigin::MiscVariable(self.cause.span);
|
||||
let coerce_target = self.next_ty_var(origin);
|
||||
let mut coercion = self.unify_and(coerce_target, target, adjust)?;
|
||||
let mut coercion = self.unify_and(coerce_target, target, |target| {
|
||||
let unsize = Adjustment {
|
||||
kind: Adjust::Unsize,
|
||||
target
|
||||
};
|
||||
match reborrow {
|
||||
None => vec![unsize],
|
||||
Some((ref deref, ref autoref)) => {
|
||||
vec![deref.clone(), autoref.clone(), unsize]
|
||||
}
|
||||
}
|
||||
})?;
|
||||
|
||||
let mut selcx = traits::SelectionContext::new(self);
|
||||
|
||||
@ -541,13 +555,16 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
Ok(coercion)
|
||||
}
|
||||
|
||||
fn coerce_from_safe_fn(&self,
|
||||
a: Ty<'tcx>,
|
||||
fn_ty_a: ty::PolyFnSig<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
to_unsafe: Adjust<'tcx>,
|
||||
normal: Adjust<'tcx>)
|
||||
-> CoerceResult<'tcx> {
|
||||
fn coerce_from_safe_fn<F, G>(&self,
|
||||
a: Ty<'tcx>,
|
||||
fn_ty_a: ty::PolyFnSig<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
to_unsafe: F,
|
||||
normal: G)
|
||||
-> CoerceResult<'tcx>
|
||||
where F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
|
||||
G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>
|
||||
{
|
||||
if let ty::TyFnPtr(fn_ty_b) = b.sty {
|
||||
match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) {
|
||||
(hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
|
||||
@ -573,7 +590,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
|
||||
|
||||
self.coerce_from_safe_fn(a, fn_ty_a, b,
|
||||
Adjust::UnsafeFnPointer, identity())
|
||||
simple(Adjust::UnsafeFnPointer), identity)
|
||||
}
|
||||
|
||||
fn coerce_from_fn_item(&self,
|
||||
@ -592,9 +609,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
ty::TyFnPtr(_) => {
|
||||
let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a);
|
||||
self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b,
|
||||
Adjust::ReifyFnPointer, Adjust::ReifyFnPointer)
|
||||
simple(Adjust::ReifyFnPointer), simple(Adjust::ReifyFnPointer))
|
||||
}
|
||||
_ => self.unify_and(a, b, identity()),
|
||||
_ => self.unify_and(a, b, identity),
|
||||
}
|
||||
}
|
||||
|
||||
@ -636,9 +653,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
let pointer_ty = self.tcx.mk_fn_ptr(converted_sig);
|
||||
debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})",
|
||||
a, b, pointer_ty);
|
||||
self.unify_and(pointer_ty, b, Adjust::ClosureFnPointer)
|
||||
self.unify_and(pointer_ty, b, simple(Adjust::ClosureFnPointer))
|
||||
}
|
||||
_ => self.unify_and(a, b, identity()),
|
||||
_ => self.unify_and(a, b, identity),
|
||||
}
|
||||
}
|
||||
|
||||
@ -653,7 +670,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
ty::TyRef(_, mt) => (true, mt),
|
||||
ty::TyRawPtr(mt) => (false, mt),
|
||||
_ => {
|
||||
return self.unify_and(a, b, identity());
|
||||
return self.unify_and(a, b, identity);
|
||||
}
|
||||
};
|
||||
|
||||
@ -666,17 +683,21 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
// Although references and unsafe ptrs have the same
|
||||
// representation, we still register an Adjust::DerefRef so that
|
||||
// regionck knows that the region for `a` must be valid here.
|
||||
self.unify_and(a_unsafe, b, if is_ref {
|
||||
Adjust::DerefRef {
|
||||
autoderefs: 1,
|
||||
autoref: Some(AutoBorrow::RawPtr(mutbl_b)),
|
||||
unsize: false,
|
||||
}
|
||||
if is_ref {
|
||||
self.unify_and(a_unsafe, b, |target| {
|
||||
vec![Adjustment {
|
||||
kind: Adjust::Deref(None),
|
||||
target: mt_a.ty
|
||||
}, Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)),
|
||||
target
|
||||
}]
|
||||
})
|
||||
} else if mt_a.mutbl != mutbl_b {
|
||||
Adjust::MutToConstPointer
|
||||
self.unify_and(a_unsafe, b, simple(Adjust::MutToConstPointer))
|
||||
} else {
|
||||
identity()
|
||||
})
|
||||
self.unify_and(a_unsafe, b, identity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -703,14 +724,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable);
|
||||
let coerce = Coerce::new(self, cause);
|
||||
let ok = self.commit_if_ok(|_| coerce.coerce(&[expr], source, target))?;
|
||||
let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?;
|
||||
|
||||
let adjustment = self.register_infer_ok_obligations(ok);
|
||||
self.apply_adjustment(expr.id, adjustment);
|
||||
|
||||
// We should now have added sufficient adjustments etc to
|
||||
// ensure that the type of expression, post-adjustment, is
|
||||
// a subtype of target.
|
||||
let (adjustments, _) = self.register_infer_ok_obligations(ok);
|
||||
self.apply_adjustments(expr, adjustments);
|
||||
Ok(target)
|
||||
}
|
||||
|
||||
@ -721,7 +738,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable);
|
||||
let coerce = Coerce::new(self, cause);
|
||||
self.probe(|_| coerce.coerce::<hir::Expr>(&[], source, target)).is_ok()
|
||||
self.probe(|_| coerce.coerce(source, target)).is_ok()
|
||||
}
|
||||
|
||||
/// Given some expressions, their known unified type and another expression,
|
||||
@ -779,10 +796,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) {
|
||||
// The only adjustment that can produce an fn item is
|
||||
// `NeverToAny`, so this should always be valid.
|
||||
self.apply_adjustment(expr.id, Adjustment {
|
||||
self.apply_adjustments(expr, vec![Adjustment {
|
||||
kind: Adjust::ReifyFnPointer,
|
||||
target: fn_ptr
|
||||
});
|
||||
}]);
|
||||
}
|
||||
return Ok(fn_ptr);
|
||||
}
|
||||
@ -796,12 +813,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// but only if the new expression has no coercion already applied to it.
|
||||
let mut first_error = None;
|
||||
if !self.tables.borrow().adjustments.contains_key(&new.id) {
|
||||
let result = self.commit_if_ok(|_| coerce.coerce(&[new], new_ty, prev_ty));
|
||||
let result = self.commit_if_ok(|_| coerce.coerce(new_ty, prev_ty));
|
||||
match result {
|
||||
Ok(ok) => {
|
||||
let adjustment = self.register_infer_ok_obligations(ok);
|
||||
self.apply_adjustment(new.id, adjustment);
|
||||
return Ok(adjustment.target);
|
||||
let (adjustments, target) = self.register_infer_ok_obligations(ok);
|
||||
self.apply_adjustments(new, adjustments);
|
||||
return Ok(target);
|
||||
}
|
||||
Err(e) => first_error = Some(e),
|
||||
}
|
||||
@ -812,25 +829,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// previous expressions, other than noop reborrows (ignoring lifetimes).
|
||||
for expr in exprs {
|
||||
let expr = expr.as_coercion_site();
|
||||
let noop = match self.tables.borrow().adjustments.get(&expr.id).map(|adj| adj.kind) {
|
||||
Some(Adjust::DerefRef {
|
||||
autoderefs: 1,
|
||||
autoref: Some(AutoBorrow::Ref(_, mutbl_adj)),
|
||||
unsize: false
|
||||
}) => {
|
||||
let noop = match self.tables.borrow().expr_adjustments(expr) {
|
||||
&[
|
||||
Adjustment { kind: Adjust::Deref(_), .. },
|
||||
Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl_adj)), .. }
|
||||
] => {
|
||||
match self.node_ty(expr.id).sty {
|
||||
ty::TyRef(_, mt_orig) => {
|
||||
// Reborrow that we can safely ignore, because
|
||||
// the next adjustment can only be a DerefRef
|
||||
// the next adjustment can only be a Deref
|
||||
// which will be merged into it.
|
||||
mutbl_adj == mt_orig.mutbl
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
Some(Adjust::NeverToAny) => true,
|
||||
Some(_) => false,
|
||||
None => true,
|
||||
&[Adjustment { kind: Adjust::NeverToAny, .. }] | &[] => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if !noop {
|
||||
@ -841,7 +856,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
match self.commit_if_ok(|_| coerce.coerce(&exprs, prev_ty, new_ty)) {
|
||||
match self.commit_if_ok(|_| coerce.coerce(prev_ty, new_ty)) {
|
||||
Err(_) => {
|
||||
// Avoid giving strange errors on failed attempts.
|
||||
if let Some(e) = first_error {
|
||||
@ -854,12 +869,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
Ok(ok) => {
|
||||
let adjustment = self.register_infer_ok_obligations(ok);
|
||||
let (adjustments, target) = self.register_infer_ok_obligations(ok);
|
||||
for expr in exprs {
|
||||
let expr = expr.as_coercion_site();
|
||||
self.apply_adjustment(expr.id, adjustment);
|
||||
self.apply_adjustments(expr, adjustments.clone());
|
||||
}
|
||||
Ok(adjustment.target)
|
||||
Ok(target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,14 +8,14 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use super::probe;
|
||||
use super::{probe, MethodCallee};
|
||||
|
||||
use check::{FnCtxt, LvalueOp, callee};
|
||||
use hir::def_id::DefId;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::traits;
|
||||
use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty};
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, OverloadedDeref};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::infer::{self, InferOk};
|
||||
use syntax_pos::Span;
|
||||
@ -45,7 +45,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
unadjusted_self_ty: Ty<'tcx>,
|
||||
pick: probe::Pick<'tcx>,
|
||||
supplied_method_types: Vec<Ty<'tcx>>)
|
||||
-> ty::MethodCallee<'tcx> {
|
||||
-> MethodCallee<'tcx> {
|
||||
debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})",
|
||||
unadjusted_self_ty,
|
||||
pick,
|
||||
@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
unadjusted_self_ty: Ty<'tcx>,
|
||||
pick: probe::Pick<'tcx>,
|
||||
supplied_method_types: Vec<Ty<'tcx>>)
|
||||
-> ty::MethodCallee<'tcx> {
|
||||
-> MethodCallee<'tcx> {
|
||||
// Adjust the self expression the user provided and obtain the adjusted type.
|
||||
let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick);
|
||||
|
||||
@ -88,19 +88,20 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
debug!("all_substs={:?}", all_substs);
|
||||
|
||||
// Create the final signature for the method, replacing late-bound regions.
|
||||
let (method_ty, method_predicates) = self.instantiate_method_sig(&pick, all_substs);
|
||||
let (method_sig, method_predicates) = self.instantiate_method_sig(&pick, all_substs);
|
||||
|
||||
// Unify the (adjusted) self type with what the method expects.
|
||||
self.unify_receivers(self_ty, method_ty.fn_sig().input(0).skip_binder());
|
||||
self.unify_receivers(self_ty, method_sig.inputs()[0]);
|
||||
|
||||
// Add any trait/regions obligations specified on the method's type parameters.
|
||||
let method_ty = self.tcx.mk_fn_ptr(ty::Binder(method_sig));
|
||||
self.add_obligations(method_ty, all_substs, &method_predicates);
|
||||
|
||||
// Create the final `MethodCallee`.
|
||||
let callee = ty::MethodCallee {
|
||||
let callee = MethodCallee {
|
||||
def_id: pick.item.def_id,
|
||||
ty: method_ty,
|
||||
substs: all_substs,
|
||||
sig: method_sig,
|
||||
};
|
||||
|
||||
if let Some(hir::MutMutable) = pick.autoref {
|
||||
@ -117,40 +118,49 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
unadjusted_self_ty: Ty<'tcx>,
|
||||
pick: &probe::Pick<'tcx>)
|
||||
-> Ty<'tcx> {
|
||||
let autoref = if let Some(mutbl) = pick.autoref {
|
||||
// Commit the autoderefs by calling `autoderef` again, but this
|
||||
// time writing the results into the various tables.
|
||||
let mut autoderef = self.autoderef(self.span, unadjusted_self_ty);
|
||||
let (_, n) = autoderef.nth(pick.autoderefs).unwrap();
|
||||
assert_eq!(n, pick.autoderefs);
|
||||
|
||||
let mut adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference);
|
||||
|
||||
let mut target = autoderef.unambiguous_final_ty();
|
||||
|
||||
if let Some(mutbl) = pick.autoref {
|
||||
let region = self.next_region_var(infer::Autoref(self.span));
|
||||
Some(AutoBorrow::Ref(region, mutbl))
|
||||
target = self.tcx.mk_ref(region, ty::TypeAndMut {
|
||||
mutbl,
|
||||
ty: target
|
||||
});
|
||||
adjustments.push(Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
|
||||
target
|
||||
});
|
||||
|
||||
if let Some(unsize_target) = pick.unsize {
|
||||
target = self.tcx.mk_ref(region, ty::TypeAndMut {
|
||||
mutbl,
|
||||
ty: unsize_target
|
||||
});
|
||||
adjustments.push(Adjustment {
|
||||
kind: Adjust::Unsize,
|
||||
target
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// No unsizing should be performed without autoref (at
|
||||
// least during method dispach). This is because we
|
||||
// currently only unsize `[T;N]` to `[T]`, and naturally
|
||||
// that must occur being a reference.
|
||||
assert!(pick.unsize.is_none());
|
||||
None
|
||||
};
|
||||
}
|
||||
|
||||
autoderef.finalize();
|
||||
|
||||
// Commit the autoderefs by calling `autoderef` again, but this
|
||||
// time writing the results into the various tables.
|
||||
let mut autoderef = self.autoderef(self.span, unadjusted_self_ty);
|
||||
let (autoderefd_ty, n) = autoderef.nth(pick.autoderefs).unwrap();
|
||||
assert_eq!(n, pick.autoderefs);
|
||||
|
||||
autoderef.unambiguous_final_ty();
|
||||
autoderef.finalize(LvaluePreference::NoPreference, self.self_expr);
|
||||
|
||||
let target = pick.unsize.unwrap_or(autoderefd_ty);
|
||||
let target = target.adjust_for_autoref(self.tcx, autoref);
|
||||
|
||||
// Write out the final adjustment.
|
||||
self.apply_adjustment(self.self_expr.id, Adjustment {
|
||||
kind: Adjust::DerefRef {
|
||||
autoderefs: pick.autoderefs,
|
||||
autoref: autoref,
|
||||
unsize: pick.unsize.is_some(),
|
||||
},
|
||||
target: target
|
||||
});
|
||||
// Write out the final adjustments.
|
||||
self.apply_adjustments(self.self_expr, adjustments);
|
||||
|
||||
target
|
||||
}
|
||||
@ -349,7 +359,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
fn instantiate_method_sig(&mut self,
|
||||
pick: &probe::Pick<'tcx>,
|
||||
all_substs: &'tcx Substs<'tcx>)
|
||||
-> (Ty<'tcx>, ty::InstantiatedPredicates<'tcx>) {
|
||||
-> (ty::FnSig<'tcx>, ty::InstantiatedPredicates<'tcx>) {
|
||||
debug!("instantiate_method_sig(pick={:?}, all_substs={:?})",
|
||||
pick,
|
||||
all_substs);
|
||||
@ -380,8 +390,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig);
|
||||
debug!("type scheme substituted, method_sig={:?}", method_sig);
|
||||
|
||||
(self.tcx.mk_fn_def(def_id, all_substs, ty::Binder(method_sig)),
|
||||
method_predicates)
|
||||
(method_sig, method_predicates)
|
||||
}
|
||||
|
||||
fn add_obligations(&mut self,
|
||||
@ -436,19 +445,23 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
// Fix up the autoderefs. Autorefs can only occur immediately preceding
|
||||
// overloaded lvalue ops, and will be fixed by them in order to get
|
||||
// the correct region.
|
||||
let autoderefs = match self.tables.borrow().adjustments.get(&expr.id) {
|
||||
Some(&Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) => autoderefs,
|
||||
Some(_) | None => 0
|
||||
};
|
||||
|
||||
if autoderefs > 0 {
|
||||
let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id));
|
||||
autoderef.nth(autoderefs).unwrap_or_else(|| {
|
||||
span_bug!(expr.span,
|
||||
"expr was deref-able {} times but now isn't?",
|
||||
autoderefs);
|
||||
});
|
||||
autoderef.finalize(PreferMutLvalue, expr);
|
||||
let mut source = self.node_ty(expr.id);
|
||||
if let Some(adjustments) = self.tables.borrow_mut().adjustments.get_mut(&expr.id) {
|
||||
let pref = LvaluePreference::PreferMutLvalue;
|
||||
for adjustment in adjustments {
|
||||
if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind {
|
||||
if let Some(ok) = self.try_overloaded_deref(expr.span, source, pref) {
|
||||
let method = self.register_infer_ok_obligations(ok);
|
||||
if let ty::TyRef(region, mt) = method.sig.output().sty {
|
||||
*deref = OverloadedDeref {
|
||||
region,
|
||||
mutbl: mt.mutbl
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
source = adjustment.target;
|
||||
}
|
||||
}
|
||||
|
||||
match expr.node {
|
||||
@ -474,13 +487,12 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
{
|
||||
debug!("convert_lvalue_op_to_mutable({:?}, {:?}, {:?}, {:?})",
|
||||
op, expr, base_expr, arg_tys);
|
||||
let method_call = ty::MethodCall::expr(expr.id);
|
||||
if !self.tables.borrow().method_map.contains_key(&method_call) {
|
||||
if !self.tables.borrow().is_method_call(expr) {
|
||||
debug!("convert_lvalue_op_to_mutable - builtin, nothing to do");
|
||||
return
|
||||
}
|
||||
|
||||
let base_ty = self.tables.borrow().adjustments.get(&base_expr.id)
|
||||
let base_ty = self.tables.borrow().expr_adjustments(base_expr).last()
|
||||
.map_or_else(|| self.node_ty(expr.id), |adj| adj.target);
|
||||
let base_ty = self.resolve_type_vars_if_possible(&base_ty);
|
||||
|
||||
@ -490,34 +502,44 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
.ty;
|
||||
|
||||
let method = self.try_overloaded_lvalue_op(
|
||||
expr.span, None, base_ty, arg_tys, PreferMutLvalue, op);
|
||||
let ok = match method {
|
||||
Some(method) => method,
|
||||
expr.span, base_ty, arg_tys, PreferMutLvalue, op);
|
||||
let method = match method {
|
||||
Some(ok) => self.register_infer_ok_obligations(ok),
|
||||
None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed")
|
||||
};
|
||||
let method = self.register_infer_ok_obligations(ok);
|
||||
debug!("convert_lvalue_op_to_mutable: method={:?}", method);
|
||||
self.tables.borrow_mut().method_map.insert(method_call, method);
|
||||
self.write_method_call(expr.id, method);
|
||||
|
||||
let (region, mutbl) = if let ty::TyRef(r, mt) = method.sig.inputs()[0].sty {
|
||||
(r, mt.mutbl)
|
||||
} else {
|
||||
span_bug!(expr.span, "input to lvalue op is not a ref?");
|
||||
};
|
||||
|
||||
// Convert the autoref in the base expr to mutable with the correct
|
||||
// region and mutability.
|
||||
if let Some(&mut Adjustment {
|
||||
ref mut target, kind: Adjust::DerefRef {
|
||||
autoref: Some(AutoBorrow::Ref(ref mut r, ref mut mutbl)), ..
|
||||
let base_expr_ty = self.node_ty(base_expr.id);
|
||||
if let Some(adjustments) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) {
|
||||
let mut source = base_expr_ty;
|
||||
for adjustment in &mut adjustments[..] {
|
||||
if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind {
|
||||
debug!("convert_lvalue_op_to_mutable: converting autoref {:?}", adjustment);
|
||||
adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
|
||||
adjustment.target = self.tcx.mk_ref(region, ty::TypeAndMut {
|
||||
ty: source,
|
||||
mutbl
|
||||
});
|
||||
}
|
||||
source = adjustment.target;
|
||||
}
|
||||
}) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) {
|
||||
debug!("convert_lvalue_op_to_mutable: converting autoref of {:?}", target);
|
||||
|
||||
// extract method return type, which will be &mut T;
|
||||
// all LB regions should have been instantiated during method lookup
|
||||
let method_sig = self.tcx.no_late_bound_regions(&method.ty.fn_sig()).unwrap();
|
||||
|
||||
*target = method_sig.inputs()[0];
|
||||
if let ty::TyRef(r_, mt) = target.sty {
|
||||
*r = r_;
|
||||
*mutbl = mt.mutbl;
|
||||
} else {
|
||||
span_bug!(expr.span, "input to lvalue op is not a ref?");
|
||||
// If we have an autoref followed by unsizing at the end, fix the unsize target.
|
||||
match adjustments[..] {
|
||||
[.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
|
||||
Adjustment { kind: Adjust::Unsize, ref mut target }] => {
|
||||
*target = method.sig.inputs()[0];
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,13 +10,12 @@
|
||||
|
||||
//! Method lookup: the secret sauce of Rust. See `README.md`.
|
||||
|
||||
use check::{FnCtxt, AdjustedRcvr};
|
||||
use check::FnCtxt;
|
||||
use hir::def::Def;
|
||||
use hir::def_id::DefId;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::traits;
|
||||
use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::infer::{self, InferOk};
|
||||
|
||||
@ -36,6 +35,18 @@ mod suggest;
|
||||
|
||||
use self::probe::IsSuggestion;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct MethodCallee<'tcx> {
|
||||
/// Impl method ID, for inherent methods, or trait method ID, otherwise.
|
||||
pub def_id: DefId,
|
||||
pub substs: &'tcx Substs<'tcx>,
|
||||
|
||||
/// Instantiated method signature, i.e. it has been
|
||||
/// substituted, normalized, and has had late-bound
|
||||
/// lifetimes replaced with inference variables.
|
||||
pub sig: ty::FnSig<'tcx>,
|
||||
}
|
||||
|
||||
pub enum MethodError<'tcx> {
|
||||
// Did not find an applicable method, but we did find various near-misses that may work.
|
||||
NoMatch(NoMatchData<'tcx>),
|
||||
@ -125,7 +136,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
supplied_method_types: Vec<ty::Ty<'tcx>>,
|
||||
call_expr: &'gcx hir::Expr,
|
||||
self_expr: &'gcx hir::Expr)
|
||||
-> Result<ty::MethodCallee<'tcx>, MethodError<'tcx>> {
|
||||
-> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
|
||||
debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
|
||||
method_name,
|
||||
self_ty,
|
||||
@ -153,29 +164,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
supplied_method_types))
|
||||
}
|
||||
|
||||
/// `lookup_in_trait_adjusted` is used for overloaded operators.
|
||||
/// `lookup_method_in_trait` is used for overloaded operators.
|
||||
/// It does a very narrow slice of what the normal probe/confirm path does.
|
||||
/// In particular, it doesn't really do any probing: it simply constructs
|
||||
/// an obligation for aparticular trait with the given self-type and checks
|
||||
/// whether that trait is implemented.
|
||||
///
|
||||
/// FIXME(#18741) -- It seems likely that we can consolidate some of this
|
||||
/// code with the other method-lookup code. In particular, autoderef on
|
||||
/// index is basically identical to autoderef with normal probes, except
|
||||
/// that the test also looks for built-in indexing. Also, the second half of
|
||||
/// this method is basically the same as confirmation.
|
||||
pub fn lookup_method_in_trait_adjusted(&self,
|
||||
span: Span,
|
||||
self_info: Option<AdjustedRcvr>,
|
||||
m_name: ast::Name,
|
||||
trait_def_id: DefId,
|
||||
self_ty: ty::Ty<'tcx>,
|
||||
opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
|
||||
-> Option<InferOk<'tcx, ty::MethodCallee<'tcx>>> {
|
||||
debug!("lookup_in_trait_adjusted(self_ty={:?}, self_info={:?}, \
|
||||
/// code with the other method-lookup code. In particular, the second half
|
||||
/// of this method is basically the same as confirmation.
|
||||
pub fn lookup_method_in_trait(&self,
|
||||
span: Span,
|
||||
m_name: ast::Name,
|
||||
trait_def_id: DefId,
|
||||
self_ty: ty::Ty<'tcx>,
|
||||
opt_input_types: Option<&[ty::Ty<'tcx>]>)
|
||||
-> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
|
||||
debug!("lookup_in_trait_adjusted(self_ty={:?}, \
|
||||
m_name={}, trait_def_id={:?})",
|
||||
self_ty,
|
||||
self_info,
|
||||
m_name,
|
||||
trait_def_id);
|
||||
|
||||
@ -225,8 +232,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// NB: Instantiate late-bound regions first so that
|
||||
// `instantiate_type_scheme` can normalize associated types that
|
||||
// may reference those regions.
|
||||
let original_method_ty = tcx.type_of(def_id);
|
||||
let fn_sig = original_method_ty.fn_sig();
|
||||
let fn_sig = tcx.type_of(def_id).fn_sig();
|
||||
let fn_sig = self.replace_late_bound_regions_with_fresh_var(span,
|
||||
infer::FnCall,
|
||||
&fn_sig).0;
|
||||
@ -237,12 +243,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
value
|
||||
}
|
||||
};
|
||||
let transformed_self_ty = fn_sig.inputs()[0];
|
||||
let method_ty = tcx.mk_fn_def(def_id, substs, ty::Binder(fn_sig));
|
||||
|
||||
debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
|
||||
method_ty,
|
||||
obligation);
|
||||
|
||||
// Register obligations for the parameters. This will include the
|
||||
// `Self` parameter, which in turn has a bound of the main trait,
|
||||
@ -265,43 +265,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
obligations.extend(traits::predicates_for_generics(cause.clone(), &bounds));
|
||||
|
||||
// Also add an obligation for the method type being well-formed.
|
||||
let method_ty = tcx.mk_fn_ptr(ty::Binder(fn_sig));
|
||||
debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
|
||||
method_ty,
|
||||
obligation);
|
||||
obligations.push(traits::Obligation::new(cause, ty::Predicate::WellFormed(method_ty)));
|
||||
|
||||
// Insert any adjustments needed (always an autoref of some mutability).
|
||||
if let Some(AdjustedRcvr { rcvr_expr, autoderefs, unsize }) = self_info {
|
||||
debug!("lookup_in_trait_adjusted: inserting adjustment if needed \
|
||||
(self-id={}, autoderefs={}, unsize={}, fty={:?})",
|
||||
rcvr_expr.id, autoderefs, unsize, original_method_ty);
|
||||
|
||||
let original_sig = original_method_ty.fn_sig();
|
||||
let autoref = match (&original_sig.input(0).skip_binder().sty,
|
||||
&transformed_self_ty.sty) {
|
||||
(&ty::TyRef(..), &ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ })) => {
|
||||
// Trait method is fn(&self) or fn(&mut self), need an
|
||||
// autoref. Pull the region etc out of the type of first argument.
|
||||
Some(AutoBorrow::Ref(region, mutbl))
|
||||
}
|
||||
_ => {
|
||||
// Trait method is fn(self), no transformation needed.
|
||||
assert!(!unsize);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
self.apply_adjustment(rcvr_expr.id, Adjustment {
|
||||
kind: Adjust::DerefRef {
|
||||
autoderefs: autoderefs,
|
||||
autoref: autoref,
|
||||
unsize: unsize
|
||||
},
|
||||
target: transformed_self_ty
|
||||
});
|
||||
}
|
||||
|
||||
let callee = ty::MethodCallee {
|
||||
let callee = MethodCallee {
|
||||
def_id: def_id,
|
||||
ty: method_ty,
|
||||
substs: trait_ref.substs,
|
||||
sig: fn_sig,
|
||||
};
|
||||
|
||||
debug!("callee = {:?}", callee);
|
||||
|
@ -52,7 +52,7 @@ can be broken down into several distinct phases:
|
||||
|
||||
While type checking a function, the intermediate types for the
|
||||
expressions, blocks, and so forth contained within the function are
|
||||
stored in `fcx.node_types` and `fcx.item_substs`. These types
|
||||
stored in `fcx.node_types` and `fcx.node_substs`. These types
|
||||
may contain unresolved type variables. After type checking is
|
||||
complete, the functions in the writeback module are used to take the
|
||||
types from this table, resolve them, and then write them into their
|
||||
@ -77,8 +77,11 @@ type parameter).
|
||||
*/
|
||||
|
||||
pub use self::Expectation::*;
|
||||
use self::autoderef::Autoderef;
|
||||
use self::callee::DeferredCallResolution;
|
||||
use self::coercion::{CoerceMany, DynamicCoerceMany};
|
||||
pub use self::compare_method::{compare_impl_method, compare_const_impl};
|
||||
use self::method::MethodCallee;
|
||||
use self::TupleArgumentsFlag::*;
|
||||
|
||||
use astconv::AstConv;
|
||||
@ -93,7 +96,6 @@ use rustc::ty::subst::{Kind, Subst, Substs};
|
||||
use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal};
|
||||
use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue};
|
||||
use rustc::ty::{self, Ty, TyCtxt, Visibility};
|
||||
use rustc::ty::{MethodCall, MethodCallee};
|
||||
use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
|
||||
use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
|
||||
use rustc::ty::maps::Providers;
|
||||
@ -168,7 +170,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
// decision. We keep these deferred resolutions grouped by the
|
||||
// def-id of the closure, so that once we decide, we can easily go
|
||||
// back and process them.
|
||||
deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolutionHandler<'gcx, 'tcx>>>>,
|
||||
deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolution<'gcx, 'tcx>>>>,
|
||||
|
||||
deferred_cast_checks: RefCell<Vec<cast::CastCheck<'tcx>>>,
|
||||
|
||||
@ -194,12 +196,6 @@ impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
trait DeferredCallResolution<'gcx, 'tcx> {
|
||||
fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>);
|
||||
}
|
||||
|
||||
type DeferredCallResolutionHandler<'gcx, 'tcx> = Box<DeferredCallResolution<'gcx, 'tcx>+'tcx>;
|
||||
|
||||
/// When type-checking an expression, we propagate downward
|
||||
/// whatever type hint we are able in the form of an `Expectation`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@ -375,13 +371,6 @@ pub enum LvalueOp {
|
||||
Index
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct AdjustedRcvr<'a> {
|
||||
pub rcvr_expr: &'a hir::Expr,
|
||||
pub autoderefs: usize,
|
||||
pub unsize: bool
|
||||
}
|
||||
|
||||
/// Tracks whether executing a node may exit normally (versus
|
||||
/// return/break/panic, which "diverge", leaving dead code in their
|
||||
/// wake). Tracked semi-automatically (through type variables marked
|
||||
@ -1729,17 +1718,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
fn record_deferred_call_resolution(&self,
|
||||
closure_def_id: DefId,
|
||||
r: DeferredCallResolutionHandler<'gcx, 'tcx>) {
|
||||
r: DeferredCallResolution<'gcx, 'tcx>) {
|
||||
let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
|
||||
deferred_call_resolutions.entry(closure_def_id).or_insert(vec![]).push(r);
|
||||
}
|
||||
|
||||
fn remove_deferred_call_resolutions(&self,
|
||||
closure_def_id: DefId)
|
||||
-> Vec<DeferredCallResolutionHandler<'gcx, 'tcx>>
|
||||
-> Vec<DeferredCallResolution<'gcx, 'tcx>>
|
||||
{
|
||||
let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
|
||||
deferred_call_resolutions.remove(&closure_def_id).unwrap_or(Vec::new())
|
||||
deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![])
|
||||
}
|
||||
|
||||
pub fn tag(&self) -> String {
|
||||
@ -1769,65 +1758,54 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
|
||||
if !substs.substs.is_noop() {
|
||||
pub fn write_method_call(&self, node_id: ast::NodeId, method: MethodCallee<'tcx>) {
|
||||
self.tables.borrow_mut().type_dependent_defs.insert(node_id, Def::Method(method.def_id));
|
||||
self.write_substs(node_id, method.substs);
|
||||
}
|
||||
|
||||
pub fn write_substs(&self, node_id: ast::NodeId, substs: &'tcx Substs<'tcx>) {
|
||||
if !substs.is_noop() {
|
||||
debug!("write_substs({}, {:?}) in fcx {}",
|
||||
node_id,
|
||||
substs,
|
||||
self.tag());
|
||||
|
||||
self.tables.borrow_mut().item_substs.insert(node_id, substs);
|
||||
self.tables.borrow_mut().node_substs.insert(node_id, substs);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_autoderef_adjustment(&self,
|
||||
node_id: ast::NodeId,
|
||||
derefs: usize,
|
||||
adjusted_ty: Ty<'tcx>) {
|
||||
self.apply_adjustment(node_id, Adjustment {
|
||||
kind: Adjust::DerefRef {
|
||||
autoderefs: derefs,
|
||||
autoref: None,
|
||||
unsize: false
|
||||
},
|
||||
target: adjusted_ty
|
||||
});
|
||||
}
|
||||
pub fn apply_adjustments(&self, expr: &hir::Expr, adj: Vec<Adjustment<'tcx>>) {
|
||||
debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj);
|
||||
|
||||
pub fn apply_adjustment(&self, node_id: ast::NodeId, adj: Adjustment<'tcx>) {
|
||||
debug!("apply_adjustment(node_id={}, adj={:?})", node_id, adj);
|
||||
|
||||
if adj.is_identity() {
|
||||
if adj.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
match self.tables.borrow_mut().adjustments.entry(node_id) {
|
||||
match self.tables.borrow_mut().adjustments.entry(expr.id) {
|
||||
Entry::Vacant(entry) => { entry.insert(adj); },
|
||||
Entry::Occupied(mut entry) => {
|
||||
debug!(" - composing on top of {:?}", entry.get());
|
||||
let composed_kind = match (entry.get().kind, adj.kind) {
|
||||
match (&entry.get()[..], &adj[..]) {
|
||||
// Applying any adjustment on top of a NeverToAny
|
||||
// is a valid NeverToAny adjustment, because it can't
|
||||
// be reached.
|
||||
(Adjust::NeverToAny, _) => Adjust::NeverToAny,
|
||||
(Adjust::DerefRef {
|
||||
autoderefs: 1,
|
||||
autoref: Some(AutoBorrow::Ref(..)),
|
||||
unsize: false
|
||||
}, Adjust::DerefRef { autoderefs, .. }) if autoderefs > 0 => {
|
||||
(&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return,
|
||||
(&[
|
||||
Adjustment { kind: Adjust::Deref(_), .. },
|
||||
Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
|
||||
], &[
|
||||
Adjustment { kind: Adjust::Deref(_), .. },
|
||||
.. // Any following adjustments are allowed.
|
||||
]) => {
|
||||
// A reborrow has no effect before a dereference.
|
||||
adj.kind
|
||||
}
|
||||
// FIXME: currently we never try to compose autoderefs
|
||||
// and ReifyFnPointer/UnsafeFnPointer, but we could.
|
||||
_ =>
|
||||
bug!("while adjusting {}, can't compose {:?} and {:?}",
|
||||
node_id, entry.get(), adj)
|
||||
};
|
||||
*entry.get_mut() = Adjustment {
|
||||
kind: composed_kind,
|
||||
target: adj.target
|
||||
bug!("while adjusting {:?}, can't compose {:?} and {:?}",
|
||||
expr, entry.get(), adj)
|
||||
};
|
||||
*entry.get_mut() = adj;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1972,16 +1950,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn opt_node_ty_substs<F>(&self,
|
||||
id: ast::NodeId,
|
||||
f: F) where
|
||||
F: FnOnce(&ty::ItemSubsts<'tcx>),
|
||||
{
|
||||
if let Some(s) = self.tables.borrow().item_substs.get(&id) {
|
||||
f(s);
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers an obligation for checking later, during regionck, that the type `ty` must
|
||||
/// outlive the region `r`.
|
||||
pub fn register_region_obligation(&self,
|
||||
@ -2169,8 +2137,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
{
|
||||
// extract method return type, which will be &T;
|
||||
// all LB regions should have been instantiated during method lookup
|
||||
let ret_ty = method.ty.fn_ret();
|
||||
let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap();
|
||||
let ret_ty = method.sig.output();
|
||||
|
||||
// method returns &T, but the type as visible to user is T, so deref
|
||||
ret_ty.builtin_deref(true, NoPreference).unwrap()
|
||||
@ -2189,32 +2156,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// consolidated.
|
||||
|
||||
let mut autoderef = self.autoderef(base_expr.span, base_ty);
|
||||
|
||||
while let Some((adj_ty, autoderefs)) = autoderef.next() {
|
||||
if let Some(final_mt) = self.try_index_step(
|
||||
MethodCall::expr(expr.id), expr, Some(AdjustedRcvr {
|
||||
rcvr_expr: base_expr,
|
||||
autoderefs,
|
||||
unsize: false
|
||||
}), base_expr.span, adj_ty, lvalue_pref, idx_ty)
|
||||
{
|
||||
autoderef.finalize(lvalue_pref, base_expr);
|
||||
return Some(final_mt);
|
||||
}
|
||||
|
||||
if let ty::TyArray(element_ty, _) = adj_ty.sty {
|
||||
autoderef.finalize(lvalue_pref, base_expr);
|
||||
let adj_ty = self.tcx.mk_slice(element_ty);
|
||||
return self.try_index_step(
|
||||
MethodCall::expr(expr.id), expr, Some(AdjustedRcvr {
|
||||
rcvr_expr: base_expr,
|
||||
autoderefs,
|
||||
unsize: true
|
||||
}), base_expr.span, adj_ty, lvalue_pref, idx_ty)
|
||||
}
|
||||
let mut result = None;
|
||||
while result.is_none() && autoderef.next().is_some() {
|
||||
result = self.try_index_step(expr, base_expr, &autoderef, lvalue_pref, idx_ty);
|
||||
}
|
||||
autoderef.unambiguous_final_ty();
|
||||
None
|
||||
autoderef.finalize();
|
||||
result
|
||||
}
|
||||
|
||||
/// To type-check `base_expr[index_expr]`, we progressively autoderef
|
||||
@ -2223,16 +2170,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
/// This loop implements one step in that search; the autoderef loop
|
||||
/// is implemented by `lookup_indexing`.
|
||||
fn try_index_step(&self,
|
||||
method_call: MethodCall,
|
||||
expr: &hir::Expr,
|
||||
base_expr: Option<AdjustedRcvr>,
|
||||
base_span: Span,
|
||||
adjusted_ty: Ty<'tcx>,
|
||||
base_expr: &hir::Expr,
|
||||
autoderef: &Autoderef<'a, 'gcx, 'tcx>,
|
||||
lvalue_pref: LvaluePreference,
|
||||
index_ty: Ty<'tcx>)
|
||||
-> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
|
||||
{
|
||||
let tcx = self.tcx;
|
||||
let adjusted_ty = autoderef.unambiguous_final_ty();
|
||||
debug!("try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \
|
||||
index_ty={:?})",
|
||||
expr,
|
||||
@ -2240,35 +2185,67 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
adjusted_ty,
|
||||
index_ty);
|
||||
|
||||
let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_span));
|
||||
|
||||
// First, try built-in indexing.
|
||||
match (adjusted_ty.builtin_index(), &index_ty.sty) {
|
||||
(Some(ty), &ty::TyUint(ast::UintTy::Us)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => {
|
||||
debug!("try_index_step: success, using built-in indexing");
|
||||
// If we had `[T; N]`, we should've caught it before unsizing to `[T]`.
|
||||
if let Some(base_expr) = base_expr {
|
||||
assert!(!base_expr.unsize);
|
||||
self.apply_autoderef_adjustment(
|
||||
base_expr.rcvr_expr.id, base_expr.autoderefs, adjusted_ty);
|
||||
}
|
||||
return Some((tcx.types.usize, ty));
|
||||
let adjustments = autoderef.adjust_steps(lvalue_pref);
|
||||
self.apply_adjustments(base_expr, adjustments);
|
||||
return Some((self.tcx.types.usize, ty));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// If some lookup succeeds, write callee into table and extract index/element
|
||||
// type from the method signature.
|
||||
// If some lookup succeeded, install method in table
|
||||
let method = self.try_overloaded_lvalue_op(
|
||||
expr.span, base_expr, adjusted_ty, &[input_ty], lvalue_pref, LvalueOp::Index);
|
||||
for &unsize in &[false, true] {
|
||||
let mut self_ty = adjusted_ty;
|
||||
if unsize {
|
||||
// We only unsize arrays here.
|
||||
if let ty::TyArray(element_ty, _) = adjusted_ty.sty {
|
||||
self_ty = self.tcx.mk_slice(element_ty);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
method.map(|ok| {
|
||||
debug!("try_index_step: success, using overloaded indexing");
|
||||
let method = self.register_infer_ok_obligations(ok);
|
||||
self.tables.borrow_mut().method_map.insert(method_call, method);
|
||||
(input_ty, self.make_overloaded_lvalue_return_type(method).ty)
|
||||
})
|
||||
// If some lookup succeeds, write callee into table and extract index/element
|
||||
// type from the method signature.
|
||||
// If some lookup succeeded, install method in table
|
||||
let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_expr.span));
|
||||
let method = self.try_overloaded_lvalue_op(
|
||||
expr.span, self_ty, &[input_ty], lvalue_pref, LvalueOp::Index);
|
||||
|
||||
let result = method.map(|ok| {
|
||||
debug!("try_index_step: success, using overloaded indexing");
|
||||
let method = self.register_infer_ok_obligations(ok);
|
||||
|
||||
let mut adjustments = autoderef.adjust_steps(lvalue_pref);
|
||||
if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
|
||||
adjustments.push(Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
|
||||
target: self.tcx.mk_ref(region, ty::TypeAndMut {
|
||||
mutbl: mt.mutbl,
|
||||
ty: adjusted_ty
|
||||
})
|
||||
});
|
||||
}
|
||||
if unsize {
|
||||
adjustments.push(Adjustment {
|
||||
kind: Adjust::Unsize,
|
||||
target: method.sig.inputs()[0]
|
||||
});
|
||||
}
|
||||
self.apply_adjustments(base_expr, adjustments);
|
||||
|
||||
self.write_method_call(expr.id, method);
|
||||
(input_ty, self.make_overloaded_lvalue_return_type(method).ty)
|
||||
});
|
||||
if result.is_some() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn resolve_lvalue_op(&self, op: LvalueOp, is_mut: bool) -> (Option<DefId>, Symbol) {
|
||||
@ -2287,16 +2264,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
fn try_overloaded_lvalue_op(&self,
|
||||
span: Span,
|
||||
base_expr: Option<AdjustedRcvr>,
|
||||
base_ty: Ty<'tcx>,
|
||||
arg_tys: &[Ty<'tcx>],
|
||||
lvalue_pref: LvaluePreference,
|
||||
op: LvalueOp)
|
||||
-> Option<InferOk<'tcx, MethodCallee<'tcx>>>
|
||||
{
|
||||
debug!("try_overloaded_lvalue_op({:?},{:?},{:?},{:?},{:?})",
|
||||
debug!("try_overloaded_lvalue_op({:?},{:?},{:?},{:?})",
|
||||
span,
|
||||
base_expr,
|
||||
base_ty,
|
||||
lvalue_pref,
|
||||
op);
|
||||
@ -2305,12 +2280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let (mut_tr, mut_op) = self.resolve_lvalue_op(op, true);
|
||||
let method = match (lvalue_pref, mut_tr) {
|
||||
(PreferMutLvalue, Some(trait_did)) => {
|
||||
self.lookup_method_in_trait_adjusted(span,
|
||||
base_expr,
|
||||
mut_op,
|
||||
trait_did,
|
||||
base_ty,
|
||||
Some(arg_tys.to_owned()))
|
||||
self.lookup_method_in_trait(span, mut_op, trait_did, base_ty, Some(arg_tys))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
@ -2319,12 +2289,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let (imm_tr, imm_op) = self.resolve_lvalue_op(op, false);
|
||||
let method = match (method, imm_tr) {
|
||||
(None, Some(trait_did)) => {
|
||||
self.lookup_method_in_trait_adjusted(span,
|
||||
base_expr,
|
||||
imm_op,
|
||||
trait_did,
|
||||
base_ty,
|
||||
Some(arg_tys.to_owned()))
|
||||
self.lookup_method_in_trait(span, imm_op, trait_did, base_ty, Some(arg_tys))
|
||||
}
|
||||
(method, _) => method,
|
||||
};
|
||||
@ -2334,13 +2299,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
fn check_method_argument_types(&self,
|
||||
sp: Span,
|
||||
method_fn_ty: Ty<'tcx>,
|
||||
callee_expr: &'gcx hir::Expr,
|
||||
method: Result<MethodCallee<'tcx>, ()>,
|
||||
args_no_rcvr: &'gcx [hir::Expr],
|
||||
tuple_arguments: TupleArgumentsFlag,
|
||||
expected: Expectation<'tcx>)
|
||||
-> Ty<'tcx> {
|
||||
if method_fn_ty.references_error() {
|
||||
let has_error = match method {
|
||||
Ok(method) => {
|
||||
method.substs.references_error() || method.sig.references_error()
|
||||
}
|
||||
Err(_) => true
|
||||
};
|
||||
if has_error {
|
||||
let err_inputs = self.err_args(args_no_rcvr.len());
|
||||
|
||||
let err_inputs = match tuple_arguments {
|
||||
@ -2350,27 +2320,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr,
|
||||
false, tuple_arguments, None);
|
||||
self.tcx.types.err
|
||||
} else {
|
||||
match method_fn_ty.sty {
|
||||
ty::TyFnDef(def_id, .., ref fty) => {
|
||||
// HACK(eddyb) ignore self in the definition (see above).
|
||||
let expected_arg_tys = self.expected_inputs_for_expected_output(
|
||||
sp,
|
||||
expected,
|
||||
fty.0.output(),
|
||||
&fty.0.inputs()[1..]
|
||||
);
|
||||
self.check_argument_types(sp, &fty.0.inputs()[1..], &expected_arg_tys[..],
|
||||
args_no_rcvr, fty.0.variadic, tuple_arguments,
|
||||
self.tcx.hir.span_if_local(def_id));
|
||||
fty.0.output()
|
||||
}
|
||||
_ => {
|
||||
span_bug!(callee_expr.span, "method without bare fn type");
|
||||
}
|
||||
}
|
||||
return self.tcx.types.err;
|
||||
}
|
||||
|
||||
let method = method.unwrap();
|
||||
// HACK(eddyb) ignore self in the definition (see above).
|
||||
let expected_arg_tys = self.expected_inputs_for_expected_output(
|
||||
sp,
|
||||
expected,
|
||||
method.sig.output(),
|
||||
&method.sig.inputs()[1..]
|
||||
);
|
||||
self.check_argument_types(sp, &method.sig.inputs()[1..], &expected_arg_tys[..],
|
||||
args_no_rcvr, method.sig.variadic, tuple_arguments,
|
||||
self.tcx.hir.span_if_local(method.def_id));
|
||||
method.sig.output()
|
||||
}
|
||||
|
||||
/// Generic function that factors out common logic from function calls,
|
||||
@ -2669,10 +2633,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
"expression with never type wound up being adjusted");
|
||||
let adj_ty = self.next_diverging_ty_var(
|
||||
TypeVariableOrigin::AdjustmentType(expr.span));
|
||||
self.apply_adjustment(expr.id, Adjustment {
|
||||
self.apply_adjustments(expr, vec![Adjustment {
|
||||
kind: Adjust::NeverToAny,
|
||||
target: adj_ty
|
||||
});
|
||||
}]);
|
||||
ty = adj_ty;
|
||||
}
|
||||
|
||||
@ -2795,17 +2759,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let expr_t = self.structurally_resolved_type(expr.span, rcvr_t);
|
||||
|
||||
let tps = tps.iter().map(|ast_ty| self.to_ty(&ast_ty)).collect::<Vec<_>>();
|
||||
let fn_ty = match self.lookup_method(method_name.span,
|
||||
method_name.node,
|
||||
expr_t,
|
||||
tps,
|
||||
expr,
|
||||
rcvr) {
|
||||
let method = match self.lookup_method(method_name.span,
|
||||
method_name.node,
|
||||
expr_t,
|
||||
tps,
|
||||
expr,
|
||||
rcvr) {
|
||||
Ok(method) => {
|
||||
let method_ty = method.ty;
|
||||
let method_call = MethodCall::expr(expr.id);
|
||||
self.tables.borrow_mut().method_map.insert(method_call, method);
|
||||
method_ty
|
||||
self.write_method_call(expr.id, method);
|
||||
Ok(method)
|
||||
}
|
||||
Err(error) => {
|
||||
if method_name.node != keywords::Invalid.name() {
|
||||
@ -2816,18 +2778,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
error,
|
||||
Some(args));
|
||||
}
|
||||
self.write_error(expr.id);
|
||||
self.tcx.types.err
|
||||
Err(())
|
||||
}
|
||||
};
|
||||
|
||||
// Call the generic checker.
|
||||
let ret_ty = self.check_method_argument_types(method_name.span, fn_ty,
|
||||
expr, &args[1..],
|
||||
DontTupleArguments,
|
||||
expected);
|
||||
|
||||
ret_ty
|
||||
self.check_method_argument_types(method_name.span, method,
|
||||
&args[1..],
|
||||
DontTupleArguments,
|
||||
expected)
|
||||
}
|
||||
|
||||
fn check_return_expr(&self, return_expr: &'gcx hir::Expr) {
|
||||
@ -2912,7 +2871,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
expr_t);
|
||||
let mut private_candidate = None;
|
||||
let mut autoderef = self.autoderef(expr.span, expr_t);
|
||||
while let Some((base_t, autoderefs)) = autoderef.next() {
|
||||
while let Some((base_t, _)) = autoderef.next() {
|
||||
match base_t.sty {
|
||||
ty::TyAdt(base_def, substs) if !base_def.is_enum() => {
|
||||
debug!("struct named {:?}", base_t);
|
||||
@ -2922,8 +2881,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
if let Some(field) = fields.iter().find(|f| f.name.to_ident() == ident) {
|
||||
let field_ty = self.field_ty(expr.span, field, substs);
|
||||
if field.vis.is_accessible_from(def_scope, self.tcx) {
|
||||
autoderef.finalize(lvalue_pref, base);
|
||||
self.apply_autoderef_adjustment(base.id, autoderefs, base_t);
|
||||
let adjustments = autoderef.adjust_steps(lvalue_pref);
|
||||
self.apply_adjustments(base, adjustments);
|
||||
autoderef.finalize();
|
||||
|
||||
self.tcx.check_stability(field.did, expr.id, expr.span);
|
||||
|
||||
@ -3020,7 +2980,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let mut private_candidate = None;
|
||||
let mut tuple_like = false;
|
||||
let mut autoderef = self.autoderef(expr.span, expr_t);
|
||||
while let Some((base_t, autoderefs)) = autoderef.next() {
|
||||
while let Some((base_t, _)) = autoderef.next() {
|
||||
let field = match base_t.sty {
|
||||
ty::TyAdt(base_def, substs) if base_def.is_struct() => {
|
||||
tuple_like = base_def.struct_variant().ctor_kind == CtorKind::Fn;
|
||||
@ -3055,8 +3015,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
};
|
||||
|
||||
if let Some(field_ty) = field {
|
||||
autoderef.finalize(lvalue_pref, base);
|
||||
self.apply_autoderef_adjustment(base.id, autoderefs, base_t);
|
||||
let adjustments = autoderef.adjust_steps(lvalue_pref);
|
||||
self.apply_adjustments(base, adjustments);
|
||||
autoderef.finalize();
|
||||
return field_ty;
|
||||
}
|
||||
}
|
||||
@ -3463,18 +3424,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
lvalue_pref);
|
||||
|
||||
if !oprnd_t.references_error() {
|
||||
oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t);
|
||||
match unop {
|
||||
hir::UnDeref => {
|
||||
oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t);
|
||||
|
||||
if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) {
|
||||
oprnd_t = mt.ty;
|
||||
} else if let Some(ok) = self.try_overloaded_deref(
|
||||
expr.span, Some(&oprnd), oprnd_t, lvalue_pref) {
|
||||
expr.span, oprnd_t, lvalue_pref) {
|
||||
let method = self.register_infer_ok_obligations(ok);
|
||||
if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
|
||||
self.apply_adjustments(oprnd, vec![Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
|
||||
target: method.sig.inputs()[0]
|
||||
}]);
|
||||
}
|
||||
oprnd_t = self.make_overloaded_lvalue_return_type(method).ty;
|
||||
self.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id),
|
||||
method);
|
||||
self.write_method_call(expr.id, method);
|
||||
} else {
|
||||
self.type_error_message(expr.span, |actual| {
|
||||
format!("type `{}` cannot be \
|
||||
@ -3484,22 +3449,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
hir::UnNot => {
|
||||
oprnd_t = self.structurally_resolved_type(oprnd.span,
|
||||
oprnd_t);
|
||||
let result = self.check_user_unop("!", "not",
|
||||
tcx.lang_items.not_trait(),
|
||||
expr, &oprnd, oprnd_t, unop);
|
||||
let result = self.check_user_unop(expr, oprnd_t, unop);
|
||||
// If it's builtin, we can reuse the type, this helps inference.
|
||||
if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) {
|
||||
oprnd_t = result;
|
||||
}
|
||||
}
|
||||
hir::UnNeg => {
|
||||
oprnd_t = self.structurally_resolved_type(oprnd.span,
|
||||
oprnd_t);
|
||||
let result = self.check_user_unop("-", "neg",
|
||||
tcx.lang_items.neg_trait(),
|
||||
expr, &oprnd, oprnd_t, unop);
|
||||
let result = self.check_user_unop(expr, oprnd_t, unop);
|
||||
// If it's builtin, we can reuse the type, this helps inference.
|
||||
if !(oprnd_t.is_integral() || oprnd_t.is_fp()) {
|
||||
oprnd_t = result;
|
||||
@ -3561,9 +3518,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
// We always require that the type provided as the value for
|
||||
// a type parameter outlives the moment of instantiation.
|
||||
self.opt_node_ty_substs(expr.id, |item_substs| {
|
||||
self.add_wf_bounds(&item_substs.substs, expr);
|
||||
});
|
||||
let substs = self.tables.borrow().node_substs(expr.id);
|
||||
self.add_wf_bounds(substs, expr);
|
||||
|
||||
ty
|
||||
}
|
||||
@ -3940,7 +3896,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
// Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
|
||||
// The newly resolved definition is written into `type_relative_path_defs`.
|
||||
// The newly resolved definition is written into `type_dependent_defs`.
|
||||
fn finish_resolving_struct_path(&self,
|
||||
qpath: &hir::QPath,
|
||||
path_span: Span,
|
||||
@ -3965,7 +3921,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
ty, def, segment);
|
||||
|
||||
// Write back the new resolution.
|
||||
self.tables.borrow_mut().type_relative_path_defs.insert(node_id, def);
|
||||
self.tables.borrow_mut().type_dependent_defs.insert(node_id, def);
|
||||
|
||||
(def, ty)
|
||||
}
|
||||
@ -3973,7 +3929,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
// Resolve associated value path into a base type and associated constant or method definition.
|
||||
// The newly resolved definition is written into `type_relative_path_defs`.
|
||||
// The newly resolved definition is written into `type_dependent_defs`.
|
||||
pub fn resolve_ty_and_def_ufcs<'b>(&self,
|
||||
qpath: &'b hir::QPath,
|
||||
node_id: ast::NodeId,
|
||||
@ -4006,7 +3962,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
};
|
||||
|
||||
// Write back the new resolution.
|
||||
self.tables.borrow_mut().type_relative_path_defs.insert(node_id, def);
|
||||
self.tables.borrow_mut().type_dependent_defs.insert(node_id, def);
|
||||
(def, Some(ty), slice::ref_slice(&**item_segment))
|
||||
}
|
||||
|
||||
@ -4386,9 +4342,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let ty = self.local_ty(span, nid);
|
||||
let ty = self.normalize_associated_types_in(span, &ty);
|
||||
self.write_ty(node_id, ty);
|
||||
self.write_substs(node_id, ty::ItemSubsts {
|
||||
substs: self.tcx.intern_substs(&[])
|
||||
});
|
||||
return ty;
|
||||
}
|
||||
_ => {}
|
||||
@ -4520,9 +4473,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
debug!("instantiate_value_path: type of {:?} is {:?}",
|
||||
node_id,
|
||||
ty_substituted);
|
||||
self.write_substs(node_id, ty::ItemSubsts {
|
||||
substs: substs
|
||||
});
|
||||
self.write_substs(node_id, substs);
|
||||
ty_substituted
|
||||
}
|
||||
|
||||
|
@ -11,12 +11,13 @@
|
||||
//! Code related to processing overloaded binary and unary operators.
|
||||
|
||||
use super::FnCtxt;
|
||||
use hir::def_id::DefId;
|
||||
use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue, TypeVariants};
|
||||
use super::method::MethodCallee;
|
||||
use rustc::ty::{self, Ty, TypeFoldable, PreferMutLvalue, TypeVariants};
|
||||
use rustc::ty::TypeVariants::{TyStr, TyRef};
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
|
||||
use rustc::infer::type_variable::TypeVariableOrigin;
|
||||
use errors;
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
use syntax::symbol::Symbol;
|
||||
use rustc::hir;
|
||||
|
||||
@ -174,8 +175,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
lhs_ty,
|
||||
is_assign);
|
||||
|
||||
let (name, trait_def_id) = self.name_and_trait_def_id(op, is_assign);
|
||||
|
||||
// NB: As we have not yet type-checked the RHS, we don't have the
|
||||
// type at hand. Make a variable to represent it. The whole reason
|
||||
// for this indirection is so that, below, we can check the expr
|
||||
@ -184,15 +183,41 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// particularly for things like `String + &String`.
|
||||
let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span));
|
||||
|
||||
let return_ty = self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var],
|
||||
Symbol::intern(name), trait_def_id,
|
||||
lhs_expr);
|
||||
let result = self.lookup_op_method(lhs_ty, &[rhs_ty_var], Op::Binary(op, is_assign));
|
||||
|
||||
// see `NB` above
|
||||
let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var);
|
||||
|
||||
let return_ty = match return_ty {
|
||||
Ok(return_ty) => return_ty,
|
||||
let return_ty = match result {
|
||||
Ok(method) => {
|
||||
let by_ref_binop = !op.node.is_by_value();
|
||||
if is_assign == IsAssign::Yes || by_ref_binop {
|
||||
if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
|
||||
let autoref = Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
|
||||
target: method.sig.inputs()[0]
|
||||
};
|
||||
self.apply_adjustments(lhs_expr, vec![autoref]);
|
||||
}
|
||||
}
|
||||
if by_ref_binop {
|
||||
if let ty::TyRef(region, mt) = method.sig.inputs()[1].sty {
|
||||
let autoref = Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
|
||||
target: method.sig.inputs()[1]
|
||||
};
|
||||
// HACK(eddyb) Bypass checks due to reborrows being in
|
||||
// some cases applied on the RHS, on top of which we need
|
||||
// to autoref, which is not allowed by apply_adjustments.
|
||||
// self.apply_adjustments(rhs_expr, vec![autoref]);
|
||||
self.tables.borrow_mut().adjustments.entry(rhs_expr.id)
|
||||
.or_insert(vec![]).push(autoref);
|
||||
}
|
||||
}
|
||||
self.write_method_call(expr.id, method);
|
||||
|
||||
method.sig.output()
|
||||
}
|
||||
Err(()) => {
|
||||
// error types are considered "builtin"
|
||||
if !lhs_ty.references_error() {
|
||||
@ -214,9 +239,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty {
|
||||
if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) &&
|
||||
self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty],
|
||||
Symbol::intern(name), trait_def_id,
|
||||
lhs_expr).is_ok() {
|
||||
self.lookup_op_method(ty_mut.ty, &[rhs_ty],
|
||||
Op::Binary(op, is_assign)).is_ok() {
|
||||
err.note(
|
||||
&format!(
|
||||
"this is a reference to a type that `{}` can be applied \
|
||||
@ -302,38 +326,39 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
pub fn check_user_unop(&self,
|
||||
op_str: &str,
|
||||
mname: &str,
|
||||
trait_did: Option<DefId>,
|
||||
ex: &'gcx hir::Expr,
|
||||
operand_expr: &'gcx hir::Expr,
|
||||
operand_ty: Ty<'tcx>,
|
||||
op: hir::UnOp)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
assert!(op.is_by_value());
|
||||
let mname = Symbol::intern(mname);
|
||||
match self.lookup_op_method(ex, operand_ty, vec![], mname, trait_did, operand_expr) {
|
||||
Ok(t) => t,
|
||||
match self.lookup_op_method(operand_ty, &[], Op::Unary(op, ex.span)) {
|
||||
Ok(method) => {
|
||||
self.write_method_call(ex.id, method);
|
||||
method.sig.output()
|
||||
}
|
||||
Err(()) => {
|
||||
let actual = self.resolve_type_vars_if_possible(&operand_ty);
|
||||
if !actual.references_error() {
|
||||
struct_span_err!(self.tcx.sess, ex.span, E0600,
|
||||
"cannot apply unary operator `{}` to type `{}`",
|
||||
op_str, actual).emit();
|
||||
op.as_str(), actual).emit();
|
||||
}
|
||||
self.tcx.types.err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn name_and_trait_def_id(&self,
|
||||
op: hir::BinOp,
|
||||
is_assign: IsAssign)
|
||||
-> (&'static str, Option<DefId>) {
|
||||
fn lookup_op_method(&self, lhs_ty: Ty<'tcx>, other_tys: &[Ty<'tcx>], op: Op)
|
||||
-> Result<MethodCallee<'tcx>, ()>
|
||||
{
|
||||
let lang = &self.tcx.lang_items;
|
||||
|
||||
if let IsAssign::Yes = is_assign {
|
||||
let span = match op {
|
||||
Op::Binary(op, _) => op.span,
|
||||
Op::Unary(_, span) => span
|
||||
};
|
||||
let (opname, trait_did) = if let Op::Binary(op, IsAssign::Yes) = op {
|
||||
match op.node {
|
||||
hir::BiAdd => ("add_assign", lang.add_assign_trait()),
|
||||
hir::BiSub => ("sub_assign", lang.sub_assign_trait()),
|
||||
@ -349,12 +374,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
hir::BiGe | hir::BiGt |
|
||||
hir::BiEq | hir::BiNe |
|
||||
hir::BiAnd | hir::BiOr => {
|
||||
span_bug!(op.span,
|
||||
span_bug!(span,
|
||||
"impossible assignment operation: {}=",
|
||||
op.node.as_str())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if let Op::Binary(op, IsAssign::No) = op {
|
||||
match op.node {
|
||||
hir::BiAdd => ("add", lang.add_trait()),
|
||||
hir::BiSub => ("sub", lang.sub_trait()),
|
||||
@ -373,59 +398,34 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
hir::BiEq => ("eq", lang.eq_trait()),
|
||||
hir::BiNe => ("ne", lang.eq_trait()),
|
||||
hir::BiAnd | hir::BiOr => {
|
||||
span_bug!(op.span, "&& and || are not overloadable")
|
||||
span_bug!(span, "&& and || are not overloadable")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_op_method(&self,
|
||||
expr: &'gcx hir::Expr,
|
||||
lhs_ty: Ty<'tcx>,
|
||||
other_tys: Vec<Ty<'tcx>>,
|
||||
opname: ast::Name,
|
||||
trait_did: Option<DefId>,
|
||||
lhs_expr: &'a hir::Expr)
|
||||
-> Result<Ty<'tcx>,()>
|
||||
{
|
||||
debug!("lookup_op_method(expr={:?}, lhs_ty={:?}, opname={:?}, \
|
||||
trait_did={:?}, lhs_expr={:?})",
|
||||
expr,
|
||||
lhs_ty,
|
||||
opname,
|
||||
trait_did,
|
||||
lhs_expr);
|
||||
|
||||
let method = match trait_did {
|
||||
Some(trait_did) => {
|
||||
let lhs_expr = Some(super::AdjustedRcvr {
|
||||
rcvr_expr: lhs_expr, autoderefs: 0, unsize: false
|
||||
});
|
||||
self.lookup_method_in_trait_adjusted(expr.span,
|
||||
lhs_expr,
|
||||
opname,
|
||||
trait_did,
|
||||
lhs_ty,
|
||||
Some(other_tys))
|
||||
}
|
||||
None => None
|
||||
} else if let Op::Unary(hir::UnNot, _) = op {
|
||||
("not", lang.not_trait())
|
||||
} else if let Op::Unary(hir::UnNeg, _) = op {
|
||||
("neg", lang.neg_trait())
|
||||
} else {
|
||||
bug!("lookup_op_method: op not supported: {:?}", op)
|
||||
};
|
||||
|
||||
debug!("lookup_op_method(lhs_ty={:?}, op={:?}, opname={:?}, trait_did={:?})",
|
||||
lhs_ty,
|
||||
op,
|
||||
opname,
|
||||
trait_did);
|
||||
|
||||
let method = trait_did.and_then(|trait_did| {
|
||||
let opname = Symbol::intern(opname);
|
||||
self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys))
|
||||
});
|
||||
|
||||
match method {
|
||||
Some(ok) => {
|
||||
let method = self.register_infer_ok_obligations(ok);
|
||||
self.select_obligations_where_possible();
|
||||
|
||||
let method_ty = method.ty;
|
||||
|
||||
// HACK(eddyb) Fully qualified path to work around a resolve bug.
|
||||
let method_call = ::rustc::ty::MethodCall::expr(expr.id);
|
||||
self.tables.borrow_mut().method_map.insert(method_call, method);
|
||||
|
||||
// extract return type for method; all late bound regions
|
||||
// should have been instantiated by now
|
||||
let ret_ty = method_ty.fn_ret();
|
||||
Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap())
|
||||
Ok(method)
|
||||
}
|
||||
None => {
|
||||
Err(())
|
||||
@ -491,12 +491,18 @@ impl BinOpCategory {
|
||||
}
|
||||
|
||||
/// Whether the binary operation is an assignment (`a += b`), or not (`a + b`)
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
enum IsAssign {
|
||||
No,
|
||||
Yes,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum Op {
|
||||
Binary(hir::BinOp, IsAssign),
|
||||
Unary(hir::UnOp, Span),
|
||||
}
|
||||
|
||||
/// Returns true if this is a built-in arithmetic operation (e.g. u32
|
||||
/// + u32, i16x4 == i16x4) and false if these types would have to be
|
||||
/// overloaded to be legal. There are two reasons that we distinguish
|
||||
|
@ -91,7 +91,7 @@ use middle::region::{CodeExtent, RegionMaps};
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::traits;
|
||||
use rustc::ty::{self, Ty, MethodCall, TypeFoldable};
|
||||
use rustc::ty::{self, Ty, TypeFoldable};
|
||||
use rustc::infer::{self, GenericKind, SubregionOrigin, VerifyBound};
|
||||
use rustc::ty::adjustment;
|
||||
use rustc::ty::wf::ImpliedBound;
|
||||
@ -520,15 +520,13 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span),
|
||||
expr_ty, expr_region);
|
||||
|
||||
let method_call = MethodCall::expr(expr.id);
|
||||
let opt_method_callee = self.tables.borrow().method_map.get(&method_call).cloned();
|
||||
let has_method_map = opt_method_callee.is_some();
|
||||
let is_method_call = self.tables.borrow().is_method_call(expr);
|
||||
|
||||
// If we are calling a method (either explicitly or via an
|
||||
// overloaded operator), check that all of the types provided as
|
||||
// arguments for its type parameters are well-formed, and all the regions
|
||||
// provided as arguments outlive the call.
|
||||
if let Some(callee) = opt_method_callee {
|
||||
if is_method_call {
|
||||
let origin = match expr.node {
|
||||
hir::ExprMethodCall(..) =>
|
||||
infer::ParameterOrigin::MethodCall,
|
||||
@ -538,66 +536,16 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
infer::ParameterOrigin::OverloadedOperator
|
||||
};
|
||||
|
||||
self.substs_wf_in_scope(origin, &callee.substs, expr.span, expr_region);
|
||||
self.type_must_outlive(infer::ExprTypeIsNotInScope(callee.ty, expr.span),
|
||||
callee.ty, expr_region);
|
||||
let substs = self.tables.borrow().node_substs(expr.id);
|
||||
self.substs_wf_in_scope(origin, substs, expr.span, expr_region);
|
||||
// Arguments (sub-expressions) are checked via `constrain_call`, below.
|
||||
}
|
||||
|
||||
// Check any autoderefs or autorefs that appear.
|
||||
let adjustment = self.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone());
|
||||
if let Some(adjustment) = adjustment {
|
||||
debug!("adjustment={:?}", adjustment);
|
||||
match adjustment.kind {
|
||||
adjustment::Adjust::DerefRef { autoderefs, ref autoref, .. } => {
|
||||
let expr_ty = self.resolve_node_type(expr.id);
|
||||
self.constrain_autoderefs(expr, autoderefs, expr_ty);
|
||||
if let Some(ref autoref) = *autoref {
|
||||
self.link_autoref(expr, autoderefs, autoref);
|
||||
|
||||
// Require that the resulting region encompasses
|
||||
// the current node.
|
||||
//
|
||||
// FIXME(#6268) remove to support nested method calls
|
||||
self.type_of_node_must_outlive(infer::AutoBorrow(expr.span),
|
||||
expr.id, expr_region);
|
||||
}
|
||||
}
|
||||
/*
|
||||
adjustment::AutoObject(_, ref bounds, ..) => {
|
||||
// Determine if we are casting `expr` to a trait
|
||||
// instance. If so, we have to be sure that the type
|
||||
// of the source obeys the new region bound.
|
||||
let source_ty = self.resolve_node_type(expr.id);
|
||||
self.type_must_outlive(infer::RelateObjectBound(expr.span),
|
||||
source_ty, bounds.region_bound);
|
||||
}
|
||||
*/
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// If necessary, constrain destructors in the unadjusted form of this
|
||||
// expression.
|
||||
let cmt_result = {
|
||||
let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
|
||||
mc.cat_expr_unadjusted(expr)
|
||||
};
|
||||
match cmt_result {
|
||||
Ok(head_cmt) => {
|
||||
self.check_safety_of_rvalue_destructor_if_necessary(head_cmt,
|
||||
expr.span);
|
||||
}
|
||||
Err(..) => {
|
||||
self.tcx.sess.delay_span_bug(expr.span, "cat_expr_unadjusted Errd");
|
||||
}
|
||||
}
|
||||
}
|
||||
let cmt_result = self.constrain_adjustments(expr);
|
||||
|
||||
// If necessary, constrain destructors in this expression. This will be
|
||||
// the adjusted form if there is an adjustment.
|
||||
let cmt_result = {
|
||||
let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
|
||||
mc.cat_expr(expr)
|
||||
};
|
||||
match cmt_result {
|
||||
Ok(head_cmt) => {
|
||||
self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, expr.span);
|
||||
@ -611,57 +559,45 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
expr, self.repeating_scope);
|
||||
match expr.node {
|
||||
hir::ExprPath(_) => {
|
||||
self.fcx.opt_node_ty_substs(expr.id, |item_substs| {
|
||||
let origin = infer::ParameterOrigin::Path;
|
||||
self.substs_wf_in_scope(origin, &item_substs.substs, expr.span, expr_region);
|
||||
});
|
||||
let substs = self.tables.borrow().node_substs(expr.id);
|
||||
let origin = infer::ParameterOrigin::Path;
|
||||
self.substs_wf_in_scope(origin, substs, expr.span, expr_region);
|
||||
}
|
||||
|
||||
hir::ExprCall(ref callee, ref args) => {
|
||||
if has_method_map {
|
||||
self.constrain_call(expr, Some(&callee),
|
||||
args.iter().map(|e| &*e), false);
|
||||
if is_method_call {
|
||||
self.constrain_call(expr, Some(&callee), args.iter().map(|e| &*e));
|
||||
} else {
|
||||
self.constrain_callee(callee.id, expr, &callee);
|
||||
self.constrain_call(expr, None,
|
||||
args.iter().map(|e| &*e), false);
|
||||
self.constrain_call(expr, None, args.iter().map(|e| &*e));
|
||||
}
|
||||
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
hir::ExprMethodCall(.., ref args) => {
|
||||
self.constrain_call(expr, Some(&args[0]),
|
||||
args[1..].iter().map(|e| &*e), false);
|
||||
self.constrain_call(expr, Some(&args[0]), args[1..].iter().map(|e| &*e));
|
||||
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
hir::ExprAssignOp(_, ref lhs, ref rhs) => {
|
||||
if has_method_map {
|
||||
self.constrain_call(expr, Some(&lhs),
|
||||
Some(&**rhs).into_iter(), false);
|
||||
if is_method_call {
|
||||
self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter());
|
||||
}
|
||||
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
hir::ExprIndex(ref lhs, ref rhs) if has_method_map => {
|
||||
self.constrain_call(expr, Some(&lhs),
|
||||
Some(&**rhs).into_iter(), true);
|
||||
hir::ExprIndex(ref lhs, ref rhs) if is_method_call => {
|
||||
self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter());
|
||||
|
||||
intravisit::walk_expr(self, expr);
|
||||
},
|
||||
|
||||
hir::ExprBinary(op, ref lhs, ref rhs) if has_method_map => {
|
||||
let implicitly_ref_args = !op.node.is_by_value();
|
||||
|
||||
// As `expr_method_call`, but the call is via an
|
||||
// overloaded op. Note that we (sadly) currently use an
|
||||
// implicit "by ref" sort of passing style here. This
|
||||
// should be converted to an adjustment!
|
||||
self.constrain_call(expr, Some(&lhs),
|
||||
Some(&**rhs).into_iter(), implicitly_ref_args);
|
||||
hir::ExprBinary(_, ref lhs, ref rhs) if is_method_call => {
|
||||
// As `ExprMethodCall`, but the call is via an overloaded op.
|
||||
self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter());
|
||||
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
@ -678,32 +614,24 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
hir::ExprUnary(op, ref lhs) if has_method_map => {
|
||||
let implicitly_ref_args = !op.is_by_value();
|
||||
|
||||
// As above.
|
||||
self.constrain_call(expr, Some(&lhs),
|
||||
None::<hir::Expr>.iter(), implicitly_ref_args);
|
||||
hir::ExprUnary(hir::UnDeref, ref base) => {
|
||||
// For *a, the lifetime of a must enclose the deref
|
||||
if is_method_call {
|
||||
self.constrain_call(expr, Some(base), None::<hir::Expr>.iter());
|
||||
}
|
||||
// For overloaded derefs, base_ty is the input to `Deref::deref`,
|
||||
// but it's a reference type uing the same region as the output.
|
||||
let base_ty = self.resolve_expr_type_adjusted(base);
|
||||
if let ty::TyRef(r_ptr, _) = base_ty.sty {
|
||||
self.mk_subregion_due_to_dereference(expr.span, expr_region, r_ptr);
|
||||
}
|
||||
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
hir::ExprUnary(hir::UnDeref, ref base) => {
|
||||
// For *a, the lifetime of a must enclose the deref
|
||||
let method_call = MethodCall::expr(expr.id);
|
||||
let base_ty = match self.tables.borrow().method_map.get(&method_call) {
|
||||
Some(method) => {
|
||||
self.constrain_call(expr, Some(&base),
|
||||
None::<hir::Expr>.iter(), true);
|
||||
// late-bound regions in overloaded method calls are instantiated
|
||||
let fn_ret = self.tcx.no_late_bound_regions(&method.ty.fn_ret());
|
||||
fn_ret.unwrap()
|
||||
}
|
||||
None => self.resolve_node_type(base.id)
|
||||
};
|
||||
if let ty::TyRef(r_ptr, _) = base_ty.sty {
|
||||
self.mk_subregion_due_to_dereference(expr.span, expr_region, r_ptr);
|
||||
}
|
||||
hir::ExprUnary(_, ref lhs) if is_method_call => {
|
||||
// As above.
|
||||
self.constrain_call(expr, Some(&lhs), None::<hir::Expr>.iter());
|
||||
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
@ -859,19 +787,15 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
fn constrain_call<'b, I: Iterator<Item=&'b hir::Expr>>(&mut self,
|
||||
call_expr: &hir::Expr,
|
||||
receiver: Option<&hir::Expr>,
|
||||
arg_exprs: I,
|
||||
implicitly_ref_args: bool) {
|
||||
arg_exprs: I) {
|
||||
//! Invoked on every call site (i.e., normal calls, method calls,
|
||||
//! and overloaded operators). Constrains the regions which appear
|
||||
//! in the type of the function. Also constrains the regions that
|
||||
//! appear in the arguments appropriately.
|
||||
|
||||
debug!("constrain_call(call_expr={:?}, \
|
||||
receiver={:?}, \
|
||||
implicitly_ref_args={})",
|
||||
debug!("constrain_call(call_expr={:?}, receiver={:?})",
|
||||
call_expr,
|
||||
receiver,
|
||||
implicitly_ref_args);
|
||||
receiver);
|
||||
|
||||
// `callee_region` is the scope representing the time in which the
|
||||
// call occurs.
|
||||
@ -889,14 +813,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
// valid for at least the lifetime of the function:
|
||||
self.type_of_node_must_outlive(infer::CallArg(arg_expr.span),
|
||||
arg_expr.id, callee_region);
|
||||
|
||||
// unfortunately, there are two means of taking implicit
|
||||
// references, and we need to propagate constraints as a
|
||||
// result. modes are going away and the "DerefArgs" code
|
||||
// should be ported to use adjustments
|
||||
if implicitly_ref_args {
|
||||
self.link_by_ref(arg_expr, callee_scope);
|
||||
}
|
||||
}
|
||||
|
||||
// as loop above, but for receiver
|
||||
@ -904,89 +820,83 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
debug!("receiver: {:?}", r);
|
||||
self.type_of_node_must_outlive(infer::CallRcvr(r.span),
|
||||
r.id, callee_region);
|
||||
if implicitly_ref_args {
|
||||
self.link_by_ref(&r, callee_scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Invoked on any auto-dereference that occurs. Checks that if this is a region pointer being
|
||||
/// Invoked on any adjustments that occur. Checks that if this is a region pointer being
|
||||
/// dereferenced, the lifetime of the pointer includes the deref expr.
|
||||
fn constrain_autoderefs(&mut self,
|
||||
deref_expr: &hir::Expr,
|
||||
derefs: usize,
|
||||
mut derefd_ty: Ty<'tcx>)
|
||||
{
|
||||
debug!("constrain_autoderefs(deref_expr={:?}, derefs={}, derefd_ty={:?})",
|
||||
deref_expr,
|
||||
derefs,
|
||||
derefd_ty);
|
||||
fn constrain_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult<mc::cmt<'tcx>> {
|
||||
debug!("constrain_adjustments(expr={:?})", expr);
|
||||
|
||||
let r_deref_expr = self.tcx.node_scope_region(deref_expr.id);
|
||||
for i in 0..derefs {
|
||||
let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
|
||||
debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs);
|
||||
let mut cmt = {
|
||||
let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
|
||||
mc.cat_expr_unadjusted(expr)?
|
||||
};
|
||||
|
||||
let method = self.tables.borrow().method_map.get(&method_call).map(|m| m.clone());
|
||||
//NOTE(@jroesch): mixed RefCell borrow causes crash
|
||||
let adjustments = self.tables.borrow().expr_adjustments(&expr).to_vec();
|
||||
if adjustments.is_empty() {
|
||||
return Ok(cmt);
|
||||
}
|
||||
|
||||
derefd_ty = match method {
|
||||
Some(method) => {
|
||||
debug!("constrain_autoderefs: #{} is overloaded, method={:?}",
|
||||
i, method);
|
||||
debug!("constrain_adjustments: adjustments={:?}", adjustments);
|
||||
|
||||
let origin = infer::ParameterOrigin::OverloadedDeref;
|
||||
self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr);
|
||||
// If necessary, constrain destructors in the unadjusted form of this
|
||||
// expression.
|
||||
self.check_safety_of_rvalue_destructor_if_necessary(cmt.clone(), expr.span);
|
||||
|
||||
// Treat overloaded autoderefs as if an AutoBorrow adjustment
|
||||
// was applied on the base type, as that is always the case.
|
||||
let fn_sig = method.ty.fn_sig();
|
||||
let fn_sig = // late-bound regions should have been instantiated
|
||||
self.tcx.no_late_bound_regions(&fn_sig).unwrap();
|
||||
let self_ty = fn_sig.inputs()[0];
|
||||
let (m, r) = match self_ty.sty {
|
||||
ty::TyRef(r, ref m) => (m.mutbl, r),
|
||||
_ => {
|
||||
span_bug!(
|
||||
deref_expr.span,
|
||||
"bad overloaded deref type {:?}",
|
||||
method.ty)
|
||||
}
|
||||
};
|
||||
let expr_region = self.tcx.node_scope_region(expr.id);
|
||||
for adjustment in adjustments {
|
||||
debug!("constrain_adjustments: adjustment={:?}, cmt={:?}",
|
||||
adjustment, cmt);
|
||||
|
||||
debug!("constrain_autoderefs: receiver r={:?} m={:?}",
|
||||
r, m);
|
||||
if let adjustment::Adjust::Deref(Some(deref)) = adjustment.kind {
|
||||
debug!("constrain_adjustments: overloaded deref: {:?}", deref);
|
||||
|
||||
{
|
||||
let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
|
||||
let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
|
||||
debug!("constrain_autoderefs: self_cmt={:?}",
|
||||
self_cmt);
|
||||
self.link_region(deref_expr.span, r,
|
||||
ty::BorrowKind::from_mutbl(m), self_cmt);
|
||||
}
|
||||
// Treat overloaded autoderefs as if an AutoBorrow adjustment
|
||||
// was applied on the base type, as that is always the case.
|
||||
let input = self.tcx.mk_ref(deref.region, ty::TypeAndMut {
|
||||
ty: cmt.ty,
|
||||
mutbl: deref.mutbl,
|
||||
});
|
||||
let output = self.tcx.mk_ref(deref.region, ty::TypeAndMut {
|
||||
ty: adjustment.target,
|
||||
mutbl: deref.mutbl,
|
||||
});
|
||||
|
||||
// Specialized version of constrain_call.
|
||||
self.type_must_outlive(infer::CallRcvr(deref_expr.span),
|
||||
self_ty, r_deref_expr);
|
||||
self.type_must_outlive(infer::CallReturn(deref_expr.span),
|
||||
fn_sig.output(), r_deref_expr);
|
||||
fn_sig.output()
|
||||
}
|
||||
None => derefd_ty
|
||||
};
|
||||
self.link_region(expr.span, deref.region,
|
||||
ty::BorrowKind::from_mutbl(deref.mutbl), cmt.clone());
|
||||
|
||||
if let ty::TyRef(r_ptr, _) = derefd_ty.sty {
|
||||
self.mk_subregion_due_to_dereference(deref_expr.span,
|
||||
r_deref_expr, r_ptr);
|
||||
// Specialized version of constrain_call.
|
||||
self.type_must_outlive(infer::CallRcvr(expr.span),
|
||||
input, expr_region);
|
||||
self.type_must_outlive(infer::CallReturn(expr.span),
|
||||
output, expr_region);
|
||||
}
|
||||
|
||||
match derefd_ty.builtin_deref(true, ty::NoPreference) {
|
||||
Some(mt) => derefd_ty = mt.ty,
|
||||
/* if this type can't be dereferenced, then there's already an error
|
||||
in the session saying so. Just bail out for now */
|
||||
None => break
|
||||
if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind {
|
||||
self.link_autoref(expr, cmt.clone(), autoref);
|
||||
|
||||
// Require that the resulting region encompasses
|
||||
// the current node.
|
||||
//
|
||||
// FIXME(#6268) remove to support nested method calls
|
||||
self.type_of_node_must_outlive(infer::AutoBorrow(expr.span),
|
||||
expr.id, expr_region);
|
||||
}
|
||||
|
||||
{
|
||||
let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
|
||||
cmt = mc.cat_expr_adjusted(expr, cmt, &adjustment)?;
|
||||
}
|
||||
|
||||
if let Categorization::Deref(_, mc::BorrowedPtr(_, r_ptr)) = cmt.cat {
|
||||
self.mk_subregion_due_to_dereference(expr.span,
|
||||
expr_region, r_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(cmt)
|
||||
}
|
||||
|
||||
pub fn mk_subregion_due_to_dereference(&mut self,
|
||||
@ -1053,7 +963,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
// is going to fail anyway, so just stop here and let typeck
|
||||
// report errors later on in the writeback phase.
|
||||
let ty0 = self.resolve_node_type(id);
|
||||
let ty = self.tables.borrow().adjustments.get(&id).map_or(ty0, |adj| adj.target);
|
||||
let ty = self.tables.borrow().adjustments.get(&id)
|
||||
.and_then(|adj| adj.last())
|
||||
.map_or(ty0, |adj| adj.target);
|
||||
let ty = self.resolve_type(ty);
|
||||
debug!("constrain_regions_in_type_of_node(\
|
||||
ty={}, ty0={}, id={}, minimum_lifetime={:?})",
|
||||
@ -1151,13 +1063,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
/// autoref'd.
|
||||
fn link_autoref(&self,
|
||||
expr: &hir::Expr,
|
||||
autoderefs: usize,
|
||||
expr_cmt: mc::cmt<'tcx>,
|
||||
autoref: &adjustment::AutoBorrow<'tcx>)
|
||||
{
|
||||
debug!("link_autoref(autoderefs={}, autoref={:?})", autoderefs, autoref);
|
||||
let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
|
||||
let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
|
||||
debug!("expr_cmt={:?}", expr_cmt);
|
||||
debug!("link_autoref(autoref={:?}, expr_cmt={:?})", autoref, expr_cmt);
|
||||
|
||||
match *autoref {
|
||||
adjustment::AutoBorrow::Ref(r, m) => {
|
||||
@ -1172,19 +1081,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the guarantor for cases where the `expr` is being passed by implicit reference and
|
||||
/// must outlive `callee_scope`.
|
||||
fn link_by_ref(&self,
|
||||
expr: &hir::Expr,
|
||||
callee_scope: CodeExtent) {
|
||||
debug!("link_by_ref(expr={:?}, callee_scope={:?})",
|
||||
expr, callee_scope);
|
||||
let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
|
||||
let expr_cmt = ignore_err!(mc.cat_expr(expr));
|
||||
let borrow_region = self.tcx.mk_region(ty::ReScope(callee_scope));
|
||||
self.link_region(expr.span, borrow_region, ty::ImmBorrow, expr_cmt);
|
||||
}
|
||||
|
||||
/// Like `link_region()`, except that the region is extracted from the type of `id`,
|
||||
/// which must be some reference (`&T`, `&str`, etc).
|
||||
fn link_region_from_node_type(&self,
|
||||
@ -1224,10 +1120,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
borrow_kind,
|
||||
borrow_cmt);
|
||||
match borrow_cmt.cat.clone() {
|
||||
Categorization::Deref(ref_cmt, _,
|
||||
mc::Implicit(ref_kind, ref_region)) |
|
||||
Categorization::Deref(ref_cmt, _,
|
||||
mc::BorrowedPtr(ref_kind, ref_region)) => {
|
||||
Categorization::Deref(ref_cmt, mc::Implicit(ref_kind, ref_region)) |
|
||||
Categorization::Deref(ref_cmt, mc::BorrowedPtr(ref_kind, ref_region)) => {
|
||||
match self.link_reborrowed_region(span,
|
||||
borrow_region, borrow_kind,
|
||||
ref_cmt, ref_region, ref_kind,
|
||||
@ -1243,7 +1137,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
Categorization::Downcast(cmt_base, _) |
|
||||
Categorization::Deref(cmt_base, _, mc::Unique) |
|
||||
Categorization::Deref(cmt_base, mc::Unique) |
|
||||
Categorization::Interior(cmt_base, _) => {
|
||||
// Borrowing interior or owned data requires the base
|
||||
// to be valid and borrowable in the same fashion.
|
||||
@ -1251,7 +1145,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
borrow_kind = borrow_kind;
|
||||
}
|
||||
|
||||
Categorization::Deref(.., mc::UnsafePtr(..)) |
|
||||
Categorization::Deref(_, mc::UnsafePtr(..)) |
|
||||
Categorization::StaticItem |
|
||||
Categorization::Upvar(..) |
|
||||
Categorization::Local(..) |
|
||||
|
@ -216,9 +216,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||
let closure_def_id = self.fcx.tcx.hir.local_def_id(id);
|
||||
debug!("closure_kind({:?}) = {:?}", closure_def_id, kind);
|
||||
|
||||
let mut deferred_call_resolutions =
|
||||
let deferred_call_resolutions =
|
||||
self.fcx.remove_deferred_call_resolutions(closure_def_id);
|
||||
for deferred_call_resolution in &mut deferred_call_resolutions {
|
||||
for deferred_call_resolution in deferred_call_resolutions {
|
||||
deferred_call_resolution.resolve(self.fcx);
|
||||
}
|
||||
}
|
||||
@ -281,8 +281,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||
debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}",
|
||||
guarantor);
|
||||
match guarantor.cat {
|
||||
Categorization::Deref(.., mc::BorrowedPtr(..)) |
|
||||
Categorization::Deref(.., mc::Implicit(..)) => {
|
||||
Categorization::Deref(_, mc::BorrowedPtr(..)) |
|
||||
Categorization::Deref(_, mc::Implicit(..)) => {
|
||||
match cmt.note {
|
||||
mc::NoteUpvarRef(upvar_id) => {
|
||||
debug!("adjust_upvar_borrow_kind_for_consume: \
|
||||
@ -327,7 +327,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||
cmt);
|
||||
|
||||
match cmt.cat.clone() {
|
||||
Categorization::Deref(base, _, mc::Unique) |
|
||||
Categorization::Deref(base, mc::Unique) |
|
||||
Categorization::Interior(base, _) |
|
||||
Categorization::Downcast(base, _) => {
|
||||
// Interior or owned data is mutable if base is
|
||||
@ -335,8 +335,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||
self.adjust_upvar_borrow_kind_for_mut(base);
|
||||
}
|
||||
|
||||
Categorization::Deref(base, _, mc::BorrowedPtr(..)) |
|
||||
Categorization::Deref(base, _, mc::Implicit(..)) => {
|
||||
Categorization::Deref(base, mc::BorrowedPtr(..)) |
|
||||
Categorization::Deref(base, mc::Implicit(..)) => {
|
||||
if !self.try_adjust_upvar_deref(cmt, ty::MutBorrow) {
|
||||
// assignment to deref of an `&mut`
|
||||
// borrowed pointer implies that the
|
||||
@ -346,7 +346,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
Categorization::Deref(.., mc::UnsafePtr(..)) |
|
||||
Categorization::Deref(_, mc::UnsafePtr(..)) |
|
||||
Categorization::StaticItem |
|
||||
Categorization::Rvalue(..) |
|
||||
Categorization::Local(_) |
|
||||
@ -361,7 +361,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||
cmt);
|
||||
|
||||
match cmt.cat.clone() {
|
||||
Categorization::Deref(base, _, mc::Unique) |
|
||||
Categorization::Deref(base, mc::Unique) |
|
||||
Categorization::Interior(base, _) |
|
||||
Categorization::Downcast(base, _) => {
|
||||
// Interior or owned data is unique if base is
|
||||
@ -369,8 +369,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||
self.adjust_upvar_borrow_kind_for_unique(base);
|
||||
}
|
||||
|
||||
Categorization::Deref(base, _, mc::BorrowedPtr(..)) |
|
||||
Categorization::Deref(base, _, mc::Implicit(..)) => {
|
||||
Categorization::Deref(base, mc::BorrowedPtr(..)) |
|
||||
Categorization::Deref(base, mc::Implicit(..)) => {
|
||||
if !self.try_adjust_upvar_deref(cmt, ty::UniqueImmBorrow) {
|
||||
// for a borrowed pointer to be unique, its
|
||||
// base must be unique
|
||||
@ -378,7 +378,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
Categorization::Deref(.., mc::UnsafePtr(..)) |
|
||||
Categorization::Deref(_, mc::UnsafePtr(..)) |
|
||||
Categorization::StaticItem |
|
||||
Categorization::Rvalue(..) |
|
||||
Categorization::Local(_) |
|
||||
|
@ -16,8 +16,7 @@ use check::FnCtxt;
|
||||
use rustc::hir;
|
||||
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use rustc::infer::{InferCtxt};
|
||||
use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee};
|
||||
use rustc::ty::adjustment;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::fold::{TypeFolder,TypeFoldable};
|
||||
use rustc::util::nodemap::DefIdSet;
|
||||
use syntax::ast;
|
||||
@ -106,7 +105,9 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
||||
let inner_ty = self.fcx.resolve_type_vars_if_possible(&inner_ty);
|
||||
|
||||
if inner_ty.is_scalar() {
|
||||
self.fcx.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
|
||||
let mut tables = self.fcx.tables.borrow_mut();
|
||||
tables.type_dependent_defs.remove(&e.id);
|
||||
tables.node_substs.remove(&e.id);
|
||||
}
|
||||
}
|
||||
hir::ExprBinary(ref op, ref lhs, ref rhs) |
|
||||
@ -118,20 +119,19 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
||||
let rhs_ty = self.fcx.resolve_type_vars_if_possible(&rhs_ty);
|
||||
|
||||
if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
|
||||
self.fcx.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
|
||||
let mut tables = self.fcx.tables.borrow_mut();
|
||||
tables.type_dependent_defs.remove(&e.id);
|
||||
tables.node_substs.remove(&e.id);
|
||||
|
||||
// weird but true: the by-ref binops put an
|
||||
// adjustment on the lhs but not the rhs; the
|
||||
// adjustment for rhs is kind of baked into the
|
||||
// system.
|
||||
match e.node {
|
||||
hir::ExprBinary(..) => {
|
||||
if !op.node.is_by_value() {
|
||||
self.fcx.tables.borrow_mut().adjustments.remove(&lhs.id);
|
||||
tables.adjustments.get_mut(&lhs.id).map(|a| a.pop());
|
||||
tables.adjustments.get_mut(&rhs.id).map(|a| a.pop());
|
||||
}
|
||||
},
|
||||
hir::ExprAssignOp(..) => {
|
||||
self.fcx.tables.borrow_mut().adjustments.remove(&lhs.id);
|
||||
tables.adjustments.get_mut(&lhs.id).map(|a| a.pop());
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
@ -164,7 +164,6 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
|
||||
self.fix_scalar_builtin_expr(e);
|
||||
|
||||
self.visit_node_id(e.span, e.id);
|
||||
self.visit_method_map_entry(e.span, MethodCall::expr(e.id));
|
||||
|
||||
if let hir::ExprClosure(_, _, body, _) = e.node {
|
||||
let body = self.fcx.tcx.hir.body(body);
|
||||
@ -280,9 +279,9 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
fn visit_node_id(&mut self, span: Span, node_id: ast::NodeId) {
|
||||
// Export associated path extensions.
|
||||
if let Some(def) = self.fcx.tables.borrow_mut().type_relative_path_defs.remove(&node_id) {
|
||||
self.tables.type_relative_path_defs.insert(node_id, def);
|
||||
// Export associated path extensions and method resultions.
|
||||
if let Some(def) = self.fcx.tables.borrow_mut().type_dependent_defs.remove(&node_id) {
|
||||
self.tables.type_dependent_defs.insert(node_id, def);
|
||||
}
|
||||
|
||||
// Resolve any borrowings for the node with id `node_id`
|
||||
@ -295,94 +294,29 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
||||
debug!("Node {} has type {:?}", node_id, n_ty);
|
||||
|
||||
// Resolve any substitutions
|
||||
self.fcx.opt_node_ty_substs(node_id, |item_substs| {
|
||||
let item_substs = self.resolve(item_substs, &span);
|
||||
if !item_substs.is_noop() {
|
||||
debug!("write_substs_to_tcx({}, {:?})", node_id, item_substs);
|
||||
assert!(!item_substs.substs.needs_infer());
|
||||
self.tables.item_substs.insert(node_id, item_substs);
|
||||
}
|
||||
});
|
||||
if let Some(&substs) = self.fcx.tables.borrow().node_substs.get(&node_id) {
|
||||
let substs = self.resolve(&substs, &span);
|
||||
debug!("write_substs_to_tcx({}, {:?})", node_id, substs);
|
||||
assert!(!substs.needs_infer());
|
||||
self.tables.node_substs.insert(node_id, substs);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_adjustments(&mut self, span: Span, node_id: ast::NodeId) {
|
||||
let adjustments = self.fcx.tables.borrow_mut().adjustments.remove(&node_id);
|
||||
match adjustments {
|
||||
let adjustment = self.fcx.tables.borrow_mut().adjustments.remove(&node_id);
|
||||
match adjustment {
|
||||
None => {
|
||||
debug!("No adjustments for node {}", node_id);
|
||||
}
|
||||
|
||||
Some(adjustment) => {
|
||||
let resolved_adjustment = match adjustment.kind {
|
||||
adjustment::Adjust::NeverToAny => {
|
||||
adjustment::Adjust::NeverToAny
|
||||
}
|
||||
|
||||
adjustment::Adjust::ReifyFnPointer => {
|
||||
adjustment::Adjust::ReifyFnPointer
|
||||
}
|
||||
|
||||
adjustment::Adjust::MutToConstPointer => {
|
||||
adjustment::Adjust::MutToConstPointer
|
||||
}
|
||||
|
||||
adjustment::Adjust::ClosureFnPointer => {
|
||||
adjustment::Adjust::ClosureFnPointer
|
||||
}
|
||||
|
||||
adjustment::Adjust::UnsafeFnPointer => {
|
||||
adjustment::Adjust::UnsafeFnPointer
|
||||
}
|
||||
|
||||
adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => {
|
||||
for autoderef in 0..autoderefs {
|
||||
let method_call = MethodCall::autoderef(node_id, autoderef as u32);
|
||||
self.visit_method_map_entry(span, method_call);
|
||||
}
|
||||
|
||||
adjustment::Adjust::DerefRef {
|
||||
autoderefs: autoderefs,
|
||||
autoref: self.resolve(&autoref, &span),
|
||||
unsize: unsize,
|
||||
}
|
||||
}
|
||||
};
|
||||
let resolved_adjustment = adjustment::Adjustment {
|
||||
kind: resolved_adjustment,
|
||||
target: self.resolve(&adjustment.target, &span)
|
||||
};
|
||||
let resolved_adjustment = self.resolve(&adjustment, &span);
|
||||
debug!("Adjustments for node {}: {:?}", node_id, resolved_adjustment);
|
||||
self.tables.adjustments.insert(node_id, resolved_adjustment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_method_map_entry(&mut self,
|
||||
method_span: Span,
|
||||
method_call: MethodCall) {
|
||||
// Resolve any method map entry
|
||||
let new_method = match self.fcx.tables.borrow_mut().method_map.remove(&method_call) {
|
||||
Some(method) => {
|
||||
debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})",
|
||||
method_call,
|
||||
method);
|
||||
let new_method = MethodCallee {
|
||||
def_id: method.def_id,
|
||||
ty: self.resolve(&method.ty, &method_span),
|
||||
substs: self.resolve(&method.substs, &method_span),
|
||||
};
|
||||
|
||||
Some(new_method)
|
||||
}
|
||||
None => None
|
||||
};
|
||||
|
||||
//NB(jroesch): We need to match twice to avoid a double borrow which would cause an ICE
|
||||
if let Some(method) = new_method {
|
||||
self.tables.method_map.insert(method_call, method);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_liberated_fn_sigs(&mut self) {
|
||||
for (&node_id, fn_sig) in self.fcx.tables.borrow().liberated_fn_sigs.iter() {
|
||||
let fn_sig = self.resolve(fn_sig, &node_id);
|
||||
|
@ -73,12 +73,14 @@ This API is completely unstable and subject to change.
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
#![feature(advanced_slice_patterns)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(conservative_impl_trait)]
|
||||
#![feature(never_type)]
|
||||
#![feature(quote)]
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
#![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))]
|
||||
#![cfg_attr(stage0, feature(rustc_private))]
|
||||
|
@ -1953,7 +1953,7 @@ mod tests {
|
||||
fn oneshot_single_thread_send_then_recv() {
|
||||
let (tx, rx) = channel::<Box<i32>>();
|
||||
tx.send(box 10).unwrap();
|
||||
assert!(rx.recv().unwrap() == box 10);
|
||||
assert!(*rx.recv().unwrap() == 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -2010,7 +2010,7 @@ mod tests {
|
||||
fn oneshot_multi_task_recv_then_send() {
|
||||
let (tx, rx) = channel::<Box<i32>>();
|
||||
let _t = thread::spawn(move|| {
|
||||
assert!(rx.recv().unwrap() == box 10);
|
||||
assert!(*rx.recv().unwrap() == 10);
|
||||
});
|
||||
|
||||
tx.send(box 10).unwrap();
|
||||
@ -2023,7 +2023,7 @@ mod tests {
|
||||
drop(tx);
|
||||
});
|
||||
let res = thread::spawn(move|| {
|
||||
assert!(rx.recv().unwrap() == box 10);
|
||||
assert!(*rx.recv().unwrap() == 10);
|
||||
}).join();
|
||||
assert!(res.is_err());
|
||||
}
|
||||
@ -2077,7 +2077,7 @@ mod tests {
|
||||
let _t = thread::spawn(move|| {
|
||||
tx.send(box 10).unwrap();
|
||||
});
|
||||
assert!(rx.recv().unwrap() == box 10);
|
||||
assert!(*rx.recv().unwrap() == 10);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2102,7 +2102,7 @@ mod tests {
|
||||
if i == 10 { return }
|
||||
|
||||
thread::spawn(move|| {
|
||||
assert!(rx.recv().unwrap() == box i);
|
||||
assert!(*rx.recv().unwrap() == i);
|
||||
recv(rx, i + 1);
|
||||
});
|
||||
}
|
||||
@ -2639,7 +2639,7 @@ mod sync_tests {
|
||||
fn oneshot_single_thread_send_then_recv() {
|
||||
let (tx, rx) = sync_channel::<Box<i32>>(1);
|
||||
tx.send(box 10).unwrap();
|
||||
assert!(rx.recv().unwrap() == box 10);
|
||||
assert!(*rx.recv().unwrap() == 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -2711,7 +2711,7 @@ mod sync_tests {
|
||||
fn oneshot_multi_task_recv_then_send() {
|
||||
let (tx, rx) = sync_channel::<Box<i32>>(0);
|
||||
let _t = thread::spawn(move|| {
|
||||
assert!(rx.recv().unwrap() == box 10);
|
||||
assert!(*rx.recv().unwrap() == 10);
|
||||
});
|
||||
|
||||
tx.send(box 10).unwrap();
|
||||
@ -2724,7 +2724,7 @@ mod sync_tests {
|
||||
drop(tx);
|
||||
});
|
||||
let res = thread::spawn(move|| {
|
||||
assert!(rx.recv().unwrap() == box 10);
|
||||
assert!(*rx.recv().unwrap() == 10);
|
||||
}).join();
|
||||
assert!(res.is_err());
|
||||
}
|
||||
@ -2778,7 +2778,7 @@ mod sync_tests {
|
||||
let _t = thread::spawn(move|| {
|
||||
tx.send(box 10).unwrap();
|
||||
});
|
||||
assert!(rx.recv().unwrap() == box 10);
|
||||
assert!(*rx.recv().unwrap() == 10);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2803,7 +2803,7 @@ mod sync_tests {
|
||||
if i == 10 { return }
|
||||
|
||||
thread::spawn(move|| {
|
||||
assert!(rx.recv().unwrap() == box i);
|
||||
assert!(*rx.recv().unwrap() == i);
|
||||
recv(rx, i + 1);
|
||||
});
|
||||
}
|
||||
|
@ -8,10 +8,10 @@ error[E0308]: mismatched types
|
||||
found type `u32`
|
||||
|
||||
error[E0277]: the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
|
||||
--> $DIR/equality.rs:34:9
|
||||
--> $DIR/equality.rs:34:11
|
||||
|
|
||||
34 | n + sum_to(n - 1)
|
||||
| ^^^^^^^^^^^^^^^^^ no implementation for `u32 + impl Foo`
|
||||
| ^ no implementation for `u32 + impl Foo`
|
||||
|
|
||||
= help: the trait `std::ops::Add<impl Foo>` is not implemented for `u32`
|
||||
|
||||
|
@ -1,56 +1,56 @@
|
||||
error[E0277]: the trait bound `{integer}: std::ops::Add<std::option::Option<{integer}>>` is not satisfied
|
||||
--> $DIR/binops.rs:12:5
|
||||
--> $DIR/binops.rs:12:7
|
||||
|
|
||||
12 | 1 + Some(1);
|
||||
| ^^^^^^^^^^^ no implementation for `{integer} + std::option::Option<{integer}>`
|
||||
| ^ no implementation for `{integer} + std::option::Option<{integer}>`
|
||||
|
|
||||
= help: the trait `std::ops::Add<std::option::Option<{integer}>>` is not implemented for `{integer}`
|
||||
|
||||
error[E0277]: the trait bound `usize: std::ops::Sub<std::option::Option<{integer}>>` is not satisfied
|
||||
--> $DIR/binops.rs:13:5
|
||||
--> $DIR/binops.rs:13:16
|
||||
|
|
||||
13 | 2 as usize - Some(1);
|
||||
| ^^^^^^^^^^^^^^^^^^^^ no implementation for `usize - std::option::Option<{integer}>`
|
||||
| ^ no implementation for `usize - std::option::Option<{integer}>`
|
||||
|
|
||||
= help: the trait `std::ops::Sub<std::option::Option<{integer}>>` is not implemented for `usize`
|
||||
|
||||
error[E0277]: the trait bound `{integer}: std::ops::Mul<()>` is not satisfied
|
||||
--> $DIR/binops.rs:14:5
|
||||
--> $DIR/binops.rs:14:7
|
||||
|
|
||||
14 | 3 * ();
|
||||
| ^^^^^^ no implementation for `{integer} * ()`
|
||||
| ^ no implementation for `{integer} * ()`
|
||||
|
|
||||
= help: the trait `std::ops::Mul<()>` is not implemented for `{integer}`
|
||||
|
||||
error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied
|
||||
--> $DIR/binops.rs:15:5
|
||||
--> $DIR/binops.rs:15:7
|
||||
|
|
||||
15 | 4 / "";
|
||||
| ^^^^^^ no implementation for `{integer} / &str`
|
||||
| ^ no implementation for `{integer} / &str`
|
||||
|
|
||||
= help: the trait `std::ops::Div<&str>` is not implemented for `{integer}`
|
||||
|
||||
error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<std::string::String>` is not satisfied
|
||||
--> $DIR/binops.rs:16:5
|
||||
--> $DIR/binops.rs:16:7
|
||||
|
|
||||
16 | 5 < String::new();
|
||||
| ^^^^^^^^^^^^^^^^^ can't compare `{integer}` with `std::string::String`
|
||||
| ^ can't compare `{integer}` with `std::string::String`
|
||||
|
|
||||
= help: the trait `std::cmp::PartialEq<std::string::String>` is not implemented for `{integer}`
|
||||
|
||||
error[E0277]: the trait bound `{integer}: std::cmp::PartialOrd<std::string::String>` is not satisfied
|
||||
--> $DIR/binops.rs:16:5
|
||||
--> $DIR/binops.rs:16:7
|
||||
|
|
||||
16 | 5 < String::new();
|
||||
| ^^^^^^^^^^^^^^^^^ can't compare `{integer}` with `std::string::String`
|
||||
| ^ can't compare `{integer}` with `std::string::String`
|
||||
|
|
||||
= help: the trait `std::cmp::PartialOrd<std::string::String>` is not implemented for `{integer}`
|
||||
|
||||
error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<std::result::Result<{integer}, _>>` is not satisfied
|
||||
--> $DIR/binops.rs:17:5
|
||||
--> $DIR/binops.rs:17:7
|
||||
|
|
||||
17 | 6 == Ok(1);
|
||||
| ^^^^^^^^^^ can't compare `{integer}` with `std::result::Result<{integer}, _>`
|
||||
| ^^ can't compare `{integer}` with `std::result::Result<{integer}, _>`
|
||||
|
|
||||
= help: the trait `std::cmp::PartialEq<std::result::Result<{integer}, _>>` is not implemented for `{integer}`
|
||||
|
||||
|
@ -1,13 +1,8 @@
|
||||
error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied
|
||||
--> $DIR/multiline-span-simple.rs:23:9
|
||||
--> $DIR/multiline-span-simple.rs:23:18
|
||||
|
|
||||
23 | foo(1 as u32 +
|
||||
| _________^
|
||||
24 | |
|
||||
25 | | bar(x,
|
||||
26 | |
|
||||
27 | | y),
|
||||
| |______________^ no implementation for `u32 + ()`
|
||||
23 | foo(1 as u32 +
|
||||
| ^ no implementation for `u32 + ()`
|
||||
|
|
||||
= help: the trait `std::ops::Add<()>` is not implemented for `u32`
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user