提交 ad91f199 编写于 作者: E Eduard Burtescu

typeck: Support multiple expressions getting coerced at the same type.

上级 3ff4c347
...@@ -82,7 +82,7 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ...@@ -82,7 +82,7 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
autoderef(fcx, autoderef(fcx,
callee_expr.span, callee_expr.span,
original_callee_ty, original_callee_ty,
Some(callee_expr), || Some(callee_expr),
UnresolvedTypeAction::Error, UnresolvedTypeAction::Error,
LvaluePreference::NoPreference, LvaluePreference::NoPreference,
|adj_ty, idx| { |adj_ty, idx| {
......
...@@ -87,6 +87,14 @@ struct Coerce<'a, 'tcx: 'a> { ...@@ -87,6 +87,14 @@ struct Coerce<'a, 'tcx: 'a> {
type CoerceResult<'tcx> = RelateResult<'tcx, Option<AutoAdjustment<'tcx>>>; type CoerceResult<'tcx> = RelateResult<'tcx, Option<AutoAdjustment<'tcx>>>;
impl<'f, 'tcx> Coerce<'f, 'tcx> { impl<'f, 'tcx> Coerce<'f, 'tcx> {
fn new(fcx: &'a FnCtxt<'a, 'tcx>, origin: TypeOrigin) -> Self {
Coerce {
fcx: fcx,
origin: origin,
unsizing_obligations: RefCell::new(vec![])
}
}
fn tcx(&self) -> &TyCtxt<'tcx> { fn tcx(&self) -> &TyCtxt<'tcx> {
self.fcx.tcx() self.fcx.tcx()
} }
...@@ -96,16 +104,17 @@ fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { ...@@ -96,16 +104,17 @@ fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
Ok(None) // No coercion required. Ok(None) // No coercion required.
} }
fn coerce(&self, fn coerce<'a, E, I>(&self,
expr_a: &hir::Expr, exprs: &E,
a: Ty<'tcx>, a: Ty<'tcx>,
b: Ty<'tcx>) b: Ty<'tcx>)
-> CoerceResult<'tcx> { -> CoerceResult<'tcx>
debug!("Coerce.tys({:?} => {:?})", // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
a, where E: Fn() -> I,
b); I: IntoIterator<Item=&'a hir::Expr> {
let a = self.fcx.infcx().shallow_resolve(a); let a = self.fcx.infcx().shallow_resolve(a);
debug!("Coerce.tys({:?} => {:?})", a, b);
// Just ignore error types. // Just ignore error types.
if a.references_error() || b.references_error() { if a.references_error() || b.references_error() {
...@@ -156,15 +165,18 @@ fn coerce(&self, ...@@ -156,15 +165,18 @@ fn coerce(&self,
/// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`. /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
/// To match `A` with `B`, autoderef will be performed, /// To match `A` with `B`, autoderef will be performed,
/// calling `deref`/`deref_mut` where necessary. /// calling `deref`/`deref_mut` where necessary.
fn coerce_borrowed_pointer(&self, fn coerce_borrowed_pointer<'a, E, I>(&self,
expr_a: &hir::Expr, span: Span,
exprs: &E,
a: Ty<'tcx>, a: Ty<'tcx>,
b: Ty<'tcx>, b: Ty<'tcx>,
mutbl_b: hir::Mutability) mutbl_b: hir::Mutability)
-> CoerceResult<'tcx> { -> CoerceResult<'tcx>
debug!("coerce_borrowed_pointer(a={:?}, b={:?})", // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
a, where E: Fn() -> I,
b); I: IntoIterator<Item=&'a hir::Expr> {
debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b);
// If we have a parameter of type `&M T_a` and the value // If we have a parameter of type `&M T_a` and the value
// provided is `expr`, we will be adding an implicit borrow, // provided is `expr`, we will be adding an implicit borrow,
...@@ -179,17 +191,15 @@ fn coerce_borrowed_pointer(&self, ...@@ -179,17 +191,15 @@ fn coerce_borrowed_pointer(&self,
_ => return self.subtype(a, b) _ => return self.subtype(a, b)
} }
let coercion = Coercion(self.origin.span()); let span = self.origin.span();
let coercion = Coercion(span);
let r_borrow = self.fcx.infcx().next_region_var(coercion); let r_borrow = self.fcx.infcx().next_region_var(coercion);
let r_borrow = self.tcx().mk_region(r_borrow); let r_borrow = self.tcx().mk_region(r_borrow);
let autoref = Some(AutoPtr(r_borrow, mutbl_b)); let autoref = Some(AutoPtr(r_borrow, mutbl_b));
let lvalue_pref = LvaluePreference::from_mutbl(mutbl_b); let lvalue_pref = LvaluePreference::from_mutbl(mutbl_b);
let mut first_error = None; let mut first_error = None;
let (_, autoderefs, success) = autoderef(self.fcx, let (_, autoderefs, success) = autoderef(self.fcx, span, a, exprs,
expr_a.span,
a,
Some(expr_a),
UnresolvedTypeAction::Ignore, UnresolvedTypeAction::Ignore,
lvalue_pref, lvalue_pref,
|inner_ty, autoderef| { |inner_ty, autoderef| {
...@@ -323,9 +333,7 @@ fn coerce_unsized(&self, ...@@ -323,9 +333,7 @@ fn coerce_unsized(&self,
} }
} }
let mut obligations = self.unsizing_obligations.borrow_mut(); *self.unsizing_obligations.borrow_mut() = leftover_predicates;
assert!(obligations.is_empty());
*obligations = leftover_predicates;
let adjustment = AutoDerefRef { let adjustment = AutoDerefRef {
autoderefs: if reborrow.is_some() { 1 } else { 0 }, autoderefs: if reborrow.is_some() { 1 } else { 0 },
...@@ -425,39 +433,48 @@ fn coerce_unsafe_ptr(&self, ...@@ -425,39 +433,48 @@ fn coerce_unsafe_ptr(&self,
} }
} }
pub fn try<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fn apply<'a, 'b, 'tcx, E, I>(coerce: &mut Coerce<'a, 'tcx>,
expr: &hir::Expr, exprs: &E,
a: Ty<'tcx>, a: Ty<'tcx>,
b: Ty<'tcx>) b: Ty<'tcx>)
-> RelateResult<'tcx, ()> { -> RelateResult<'tcx, Ty<'tcx>>
debug!("coercion::try({:?} -> {:?})", a, b); where E: Fn() -> I,
let mut unsizing_obligations = vec![]; I: IntoIterator<Item=&'b hir::Expr> {
let adjustment = try!(indent(|| {
fcx.infcx().commit_if_ok(|_| { let (ty, adjustment) = try!(indent(|| coerce.coerce(exprs, a, b)));
let coerce = Coerce {
fcx: fcx,
origin: TypeOrigin::ExprAssignable(expr.span),
unsizing_obligations: RefCell::new(vec![])
};
let adjustment = try!(coerce.coerce(expr, a, b));
unsizing_obligations = coerce.unsizing_obligations.into_inner();
Ok(adjustment)
})
}));
if let Some(AdjustDerefRef(auto)) = adjustment { let fcx = coerce.fcx;
if let AdjustDerefRef(auto) = adjustment {
if auto.unsize.is_some() { if auto.unsize.is_some() {
for obligation in unsizing_obligations { for obligation in coerce.unsizing_obligations.borrow_mut().drain() {
fcx.register_predicate(obligation); fcx.register_predicate(obligation);
} }
} }
} }
if let Some(adjustment) = adjustment { if !adjustment.is_identity() {
debug!("Success, coerced with {:?}", adjustment); debug!("Success, coerced with {:?}", adjustment);
for expr in exprs() {
assert!(!fcx.inh.tables.borrow().adjustments.contains(&expr.id));
fcx.write_adjustment(expr.id, adjustment); fcx.write_adjustment(expr.id, adjustment);
} }
Ok(()) }
Ok(ty)
}
/// Attempt to coerce an expression from a type (a) to another type (b).
/// Adjustments are only recorded if the coercion was successful.
/// The expressions *must not* have any pre-existing adjustments.
pub fn try<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
expr: &hir::Expr,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> RelateResult<'tcx, ()> {
debug!("coercion::try({:?} -> {:?})", a, b);
let mut coerce = Coerce::new(fcx, TypeOrigin::ExprAssignable(expr.span));
fcx.infcx().commit_if_ok(|_| {
apply(&mut coerce, &|| Some(expr), a, b)
}).map(|_| ())
} }
fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
......
...@@ -158,7 +158,7 @@ fn adjust_self_ty(&mut self, ...@@ -158,7 +158,7 @@ fn adjust_self_ty(&mut self,
let (autoderefd_ty, n, result) = check::autoderef(self.fcx, let (autoderefd_ty, n, result) = check::autoderef(self.fcx,
self.span, self.span,
unadjusted_self_ty, unadjusted_self_ty,
Some(self.self_expr), || Some(self.self_expr),
UnresolvedTypeAction::Error, UnresolvedTypeAction::Error,
NoPreference, NoPreference,
|_, n| { |_, n| {
...@@ -287,7 +287,7 @@ fn extract_trait_ref<R, F>(&mut self, self_ty: Ty<'tcx>, mut closure: F) -> R wh ...@@ -287,7 +287,7 @@ fn extract_trait_ref<R, F>(&mut self, self_ty: Ty<'tcx>, mut closure: F) -> R wh
let (_, _, result) = check::autoderef(self.fcx, let (_, _, result) = check::autoderef(self.fcx,
self.span, self.span,
self_ty, self_ty,
None, || None,
UnresolvedTypeAction::Error, UnresolvedTypeAction::Error,
NoPreference, NoPreference,
|ty, _| { |ty, _| {
...@@ -509,7 +509,7 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self, ...@@ -509,7 +509,7 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self,
check::autoderef(self.fcx, check::autoderef(self.fcx,
expr.span, expr.span,
self.fcx.expr_ty(expr), self.fcx.expr_ty(expr),
Some(expr), || Some(expr),
UnresolvedTypeAction::Error, UnresolvedTypeAction::Error,
PreferMutLvalue, PreferMutLvalue,
|_, autoderefs| { |_, autoderefs| {
...@@ -522,7 +522,9 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self, ...@@ -522,7 +522,9 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self,
} }
// Don't retry the first one or we might infinite loop! // Don't retry the first one or we might infinite loop!
if i != 0 { if i == 0 {
continue;
}
match expr.node { match expr.node {
hir::ExprIndex(ref base_expr, ref index_expr) => { hir::ExprIndex(ref base_expr, ref index_expr) => {
// If this is an overloaded index, the // If this is an overloaded index, the
...@@ -597,20 +599,20 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self, ...@@ -597,20 +599,20 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self,
// a preference for mut // a preference for mut
let method_call = ty::MethodCall::expr(expr.id); let method_call = ty::MethodCall::expr(expr.id);
if self.fcx.inh.tables.borrow().method_map.contains_key(&method_call) { if self.fcx.inh.tables.borrow().method_map.contains_key(&method_call) {
check::try_overloaded_deref( let method = check::try_overloaded_deref(
self.fcx, self.fcx,
expr.span, expr.span,
Some(method_call),
Some(&base_expr), Some(&base_expr),
self.fcx.expr_ty(&base_expr), self.fcx.expr_ty(&base_expr),
PreferMutLvalue); PreferMutLvalue);
let method = method.expect("re-trying deref failed");
self.fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
} }
} }
_ => {} _ => {}
} }
} }
} }
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// MISCELLANY // MISCELLANY
......
...@@ -200,7 +200,7 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ...@@ -200,7 +200,7 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
let (final_ty, dereferences, _) = check::autoderef(fcx, let (final_ty, dereferences, _) = check::autoderef(fcx,
span, span,
self_ty, self_ty,
None, || None,
UnresolvedTypeAction::Error, UnresolvedTypeAction::Error,
NoPreference, NoPreference,
|t, d| { |t, d| {
......
...@@ -351,7 +351,7 @@ fn is_local(ty: Ty) -> bool { ...@@ -351,7 +351,7 @@ fn is_local(ty: Ty) -> bool {
return is_local(fcx.resolve_type_vars_if_possible(rcvr_ty)); return is_local(fcx.resolve_type_vars_if_possible(rcvr_ty));
} }
check::autoderef(fcx, span, rcvr_ty, None, check::autoderef(fcx, span, rcvr_ty, || None,
check::UnresolvedTypeAction::Ignore, ty::NoPreference, check::UnresolvedTypeAction::Ignore, ty::NoPreference,
|ty, _| { |ty, _| {
if is_local(ty) { if is_local(ty) {
......
...@@ -2053,20 +2053,21 @@ pub enum UnresolvedTypeAction { ...@@ -2053,20 +2053,21 @@ pub enum UnresolvedTypeAction {
/// ///
/// Note: this method does not modify the adjustments table. The caller is responsible for /// Note: this method does not modify the adjustments table. The caller is responsible for
/// inserting an AutoAdjustment record into the `fcx` using one of the suitable methods. /// inserting an AutoAdjustment record into the `fcx` using one of the suitable methods.
pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, pub fn autoderef<'a, 'b, 'tcx, E, I, T, F>(fcx: &FnCtxt<'a, 'tcx>,
sp: Span, sp: Span,
base_ty: Ty<'tcx>, base_ty: Ty<'tcx>,
opt_expr: Option<&hir::Expr>, maybe_exprs: E,
unresolved_type_action: UnresolvedTypeAction, unresolved_type_action: UnresolvedTypeAction,
mut lvalue_pref: LvaluePreference, mut lvalue_pref: LvaluePreference,
mut should_stop: F) mut should_stop: F)
-> (Ty<'tcx>, usize, Option<T>) -> (Ty<'tcx>, usize, Option<T>)
where F: FnMut(Ty<'tcx>, usize) -> Option<T>, // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
where E: Fn() -> I,
I: IntoIterator<Item=&'b hir::Expr>,
F: FnMut(Ty<'tcx>, usize) -> Option<T>,
{ {
debug!("autoderef(base_ty={:?}, opt_expr={:?}, lvalue_pref={:?})", debug!("autoderef(base_ty={:?}, lvalue_pref={:?})",
base_ty, base_ty, lvalue_pref);
opt_expr,
lvalue_pref);
let mut t = base_ty; let mut t = base_ty;
for autoderefs in 0..fcx.tcx().sess.recursion_limit.get() { for autoderefs in 0..fcx.tcx().sess.recursion_limit.get() {
...@@ -2092,11 +2093,6 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, ...@@ -2092,11 +2093,6 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
} }
// Otherwise, deref if type is derefable: // Otherwise, deref if type is derefable:
let mt = match resolved_t.builtin_deref(false, lvalue_pref) {
Some(mt) => Some(mt),
None => {
let method_call =
opt_expr.map(|expr| MethodCall::autoderef(expr.id, autoderefs as u32));
// Super subtle: it might seem as though we should // Super subtle: it might seem as though we should
// pass `opt_expr` to `try_overloaded_deref`, so that // pass `opt_expr` to `try_overloaded_deref`, so that
...@@ -2109,19 +2105,24 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, ...@@ -2109,19 +2105,24 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
// when they encounter an overloaded autoderef, have // when they encounter an overloaded autoderef, have
// to do some reconstructive surgery. This is a pretty // to do some reconstructive surgery. This is a pretty
// complex mess that is begging for a proper MIR. // complex mess that is begging for a proper MIR.
try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref) let mt = if let Some(mt) = resolved_t.builtin_deref(false, lvalue_pref) {
mt
} else if let Some(method) = try_overloaded_deref(fcx, sp, None,
resolved_t, lvalue_pref) {
for expr in maybe_exprs() {
let method_call = MethodCall::autoderef(expr.id, autoderefs as u32);
fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
} }
make_overloaded_lvalue_return_type(fcx.tcx(), method)
} else {
return (resolved_t, autoderefs, None);
}; };
match mt {
Some(mt) => {
t = mt.ty; t = mt.ty;
if mt.mutbl == hir::MutImmutable { if mt.mutbl == hir::MutImmutable {
lvalue_pref = NoPreference; lvalue_pref = NoPreference;
} }
} }
None => return (resolved_t, autoderefs, None)
}
}
// We've reached the recursion limit, error gracefully. // We've reached the recursion limit, error gracefully.
span_err!(fcx.tcx().sess, sp, E0055, span_err!(fcx.tcx().sess, sp, E0055,
...@@ -2132,11 +2133,10 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, ...@@ -2132,11 +2133,10 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span, span: Span,
method_call: Option<MethodCall>,
base_expr: Option<&hir::Expr>, base_expr: Option<&hir::Expr>,
base_ty: Ty<'tcx>, base_ty: Ty<'tcx>,
lvalue_pref: LvaluePreference) lvalue_pref: LvaluePreference)
-> Option<ty::TypeAndMut<'tcx>> -> Option<MethodCallee<'tcx>>
{ {
// Try DerefMut first, if preferred. // Try DerefMut first, if preferred.
let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) { let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
...@@ -2158,33 +2158,23 @@ fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ...@@ -2158,33 +2158,23 @@ fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
(method, _) => method (method, _) => method
}; };
make_overloaded_lvalue_return_type(fcx, method_call, method) method
} }
/// For the overloaded lvalue expressions (`*x`, `x[3]`), the trait returns a type of `&T`, but the /// For the overloaded lvalue expressions (`*x`, `x[3]`), the trait returns a type of `&T`, but the
/// actual type we assign to the *expression* is `T`. So this function just peels off the return /// actual type we assign to the *expression* is `T`. So this function just peels off the return
/// type by one layer to yield `T`. It also inserts the `method-callee` into the method map. /// type by one layer to yield `T`.
fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fn make_overloaded_lvalue_return_type<'tcx>(tcx: &ty::ctxt<'tcx>,
method_call: Option<MethodCall>, method: MethodCallee<'tcx>)
method: Option<MethodCallee<'tcx>>) -> ty::TypeAndMut<'tcx>
-> Option<ty::TypeAndMut<'tcx>>
{ {
match method {
Some(method) => {
// extract method return type, which will be &T; // extract method return type, which will be &T;
// all LB regions should have been instantiated during method lookup // all LB regions should have been instantiated during method lookup
let ret_ty = method.ty.fn_ret(); let ret_ty = method.ty.fn_ret();
let ret_ty = fcx.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap(); let ret_ty = tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap();
if let Some(method_call) = method_call {
fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
}
// method returns &T, but the type as visible to user is T, so deref // method returns &T, but the type as visible to user is T, so deref
ret_ty.builtin_deref(true, NoPreference) ret_ty.builtin_deref(true, NoPreference).unwrap()
}
None => None,
}
} }
fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
...@@ -2202,7 +2192,7 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ...@@ -2202,7 +2192,7 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
let (ty, autoderefs, final_mt) = autoderef(fcx, let (ty, autoderefs, final_mt) = autoderef(fcx,
base_expr.span, base_expr.span,
base_ty, base_ty,
Some(base_expr), || Some(base_expr),
UnresolvedTypeAction::Error, UnresolvedTypeAction::Error,
lvalue_pref, lvalue_pref,
|adj_ty, idx| { |adj_ty, idx| {
...@@ -2299,10 +2289,10 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ...@@ -2299,10 +2289,10 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
// If some lookup succeeds, write callee into table and extract index/element // If some lookup succeeds, write callee into table and extract index/element
// type from the method signature. // type from the method signature.
// If some lookup succeeded, install method in table // If some lookup succeeded, install method in table
method.and_then(|method| { method.map(|method| {
debug!("try_index_step: success, using overloaded indexing"); debug!("try_index_step: success, using overloaded indexing");
make_overloaded_lvalue_return_type(fcx, Some(method_call), Some(method)). fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
map(|ret| (input_ty, ret.ty)) (input_ty, make_overloaded_lvalue_return_type(fcx.tcx(), method).ty)
}) })
} }
...@@ -2907,7 +2897,7 @@ fn check_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, ...@@ -2907,7 +2897,7 @@ fn check_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
let (_, autoderefs, field_ty) = autoderef(fcx, let (_, autoderefs, field_ty) = autoderef(fcx,
expr.span, expr.span,
expr_t, expr_t,
Some(base), || Some(base),
UnresolvedTypeAction::Error, UnresolvedTypeAction::Error,
lvalue_pref, lvalue_pref,
|base_t, _| { |base_t, _| {
...@@ -3005,7 +2995,7 @@ fn check_tup_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, ...@@ -3005,7 +2995,7 @@ fn check_tup_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
let (_, autoderefs, field_ty) = autoderef(fcx, let (_, autoderefs, field_ty) = autoderef(fcx,
expr.span, expr.span,
expr_t, expr_t,
Some(base), || Some(base),
UnresolvedTypeAction::Error, UnresolvedTypeAction::Error,
lvalue_pref, lvalue_pref,
|base_t, _| { |base_t, _| {
...@@ -3253,22 +3243,22 @@ fn check_expr_struct<'a, 'tcx>(fcx: &FnCtxt<'a,'tcx>, ...@@ -3253,22 +3243,22 @@ fn check_expr_struct<'a, 'tcx>(fcx: &FnCtxt<'a,'tcx>,
match unop { match unop {
hir::UnDeref => { hir::UnDeref => {
oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t); oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t);
oprnd_t = match oprnd_t.builtin_deref(true, NoPreference) {
Some(mt) => mt.ty, if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) {
None => match try_overloaded_deref(fcx, expr.span, oprnd_t = mt.ty;
Some(MethodCall::expr(expr.id)), } else if let Some(method) = try_overloaded_deref(
Some(&oprnd), oprnd_t, lvalue_pref) { fcx, expr.span, Some(&oprnd), oprnd_t, lvalue_pref) {
Some(mt) => mt.ty, oprnd_t = make_overloaded_lvalue_return_type(tcx, method).ty;
None => { fcx.inh.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id),
method);
} else {
fcx.type_error_message(expr.span, |actual| { fcx.type_error_message(expr.span, |actual| {
format!("type `{}` cannot be \ format!("type `{}` cannot be \
dereferenced", actual) dereferenced", actual)
}, oprnd_t, None); }, oprnd_t, None);
tcx.types.err oprnd_t = tcx.types.err;
} }
} }
};
}
hir::UnNot => { hir::UnNot => {
oprnd_t = structurally_resolved_type(fcx, oprnd.span, oprnd_t = structurally_resolved_type(fcx, oprnd.span,
oprnd_t); oprnd_t);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册