use rustc::ty::subst::Substs;
use rustc::traits;
use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty};
-use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr};
+use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
use rustc::ty::fold::TypeFoldable;
use rustc::infer::{self, InferOk, TypeOrigin};
use syntax_pos::Span;
use std::ops::Deref;
-struct ConfirmContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a>{
+struct ConfirmContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
span: Span,
self_expr: &'gcx hir::Expr,
unadjusted_self_ty: Ty<'tcx>,
pick: probe::Pick<'tcx>,
supplied_method_types: Vec<Ty<'tcx>>)
- -> ty::MethodCallee<'tcx>
- {
+ -> ty::MethodCallee<'tcx> {
debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})",
unadjusted_self_ty,
pick,
span: Span,
self_expr: &'gcx hir::Expr,
call_expr: &'gcx hir::Expr)
- -> ConfirmContext<'a, 'gcx, 'tcx>
- {
- ConfirmContext { fcx: fcx, span: span, self_expr: self_expr, call_expr: call_expr }
+ -> ConfirmContext<'a, 'gcx, 'tcx> {
+ ConfirmContext {
+ fcx: fcx,
+ span: span,
+ self_expr: self_expr,
+ call_expr: call_expr,
+ }
}
fn confirm(&mut self,
unadjusted_self_ty: Ty<'tcx>,
pick: probe::Pick<'tcx>,
supplied_method_types: Vec<Ty<'tcx>>)
- -> ty::MethodCallee<'tcx>
- {
+ -> ty::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);
// Create substitutions for the method's type parameters.
let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick);
- let all_substs =
- self.instantiate_method_substs(
- &pick,
- supplied_method_types,
- rcvr_substs);
+ let all_substs = self.instantiate_method_substs(&pick, supplied_method_types, rcvr_substs);
debug!("all_substs={:?}", all_substs);
// Create the final signature for the method, replacing late-bound regions.
- let InstantiatedMethodSig {
- method_sig, method_predicates
- } = self.instantiate_method_sig(&pick, all_substs);
+ let InstantiatedMethodSig { method_sig, method_predicates } =
+ self.instantiate_method_sig(&pick, all_substs);
let method_self_ty = method_sig.inputs[0];
// Unify the (adjusted) self type with what the method expects.
// Create the method type
let def_id = pick.item.def_id();
let method_ty = pick.item.as_opt_method().unwrap();
- let fty = self.tcx.mk_fn_def(def_id, all_substs,
+ let fty = self.tcx.mk_fn_def(def_id,
+ all_substs,
self.tcx.mk_bare_fn(ty::BareFnTy {
- sig: ty::Binder(method_sig),
- unsafety: method_ty.fty.unsafety,
- abi: method_ty.fty.abi.clone(),
- }));
+ sig: ty::Binder(method_sig),
+ unsafety: method_ty.fty.unsafety,
+ abi: method_ty.fty.abi.clone(),
+ }));
// Add any trait/regions obligations specified on the method's type parameters.
self.add_obligations(fty, all_substs, &method_predicates);
let callee = ty::MethodCallee {
def_id: def_id,
ty: fty,
- substs: all_substs
+ substs: all_substs,
};
if let Some(hir::MutMutable) = pick.autoref {
fn adjust_self_ty(&mut self,
unadjusted_self_ty: Ty<'tcx>,
pick: &probe::Pick<'tcx>)
- -> Ty<'tcx>
- {
- let (autoref, unsize) = if let Some(mutbl) = pick.autoref {
+ -> Ty<'tcx> {
+ let autoref = if let Some(mutbl) = pick.autoref {
let region = self.next_region_var(infer::Autoref(self.span));
- let autoref = AutoPtr(region, mutbl);
- (Some(autoref), pick.unsize.map(|target| {
- target.adjust_for_autoref(self.tcx, Some(autoref))
- }))
+ Some(AutoBorrow::Ref(region, mutbl))
} 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, None)
+ None
};
+
// 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);
autoderef.unambiguous_final_ty();
autoderef.finalize(LvaluePreference::NoPreference, Some(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.write_adjustment(self.self_expr.id, AdjustDerefRef(AutoDerefRef {
- autoderefs: pick.autoderefs,
- autoref: autoref,
- unsize: unsize
- }));
-
- if let Some(target) = unsize {
- target
- } else {
- autoderefd_ty.adjust_for_autoref(self.tcx, autoref)
- }
+ self.write_adjustment(self.self_expr.id, Adjustment {
+ kind: Adjust::DerefRef {
+ autoderefs: pick.autoderefs,
+ autoref: autoref,
+ unsize: pick.unsize.is_some(),
+ },
+ target: target
+ });
+
+ target
}
///////////////////////////////////////////////////////////////////////////
fn fresh_receiver_substs(&mut self,
self_ty: Ty<'tcx>,
pick: &probe::Pick<'tcx>)
- -> &'tcx Substs<'tcx>
- {
+ -> &'tcx Substs<'tcx> {
match pick.kind {
probe::InherentImplPick => {
let impl_def_id = pick.item.container().id();
assert!(self.tcx.impl_trait_ref(impl_def_id).is_none(),
- "impl {:?} is not an inherent impl", impl_def_id);
+ "impl {:?} is not an inherent impl",
+ impl_def_id);
self.impl_self_ty(self.span, impl_def_id).substs
}
// argument type), but those cases have already
// been ruled out when we deemed the trait to be
// "object safe".
- let original_poly_trait_ref =
- principal.with_self_ty(this.tcx, object_ty);
- let upcast_poly_trait_ref =
- this.upcast(original_poly_trait_ref, trait_def_id);
+ let original_poly_trait_ref = principal.with_self_ty(this.tcx, object_ty);
+ let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id);
let upcast_trait_ref =
this.replace_late_bound_regions_with_fresh_var(&upcast_poly_trait_ref);
debug!("original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}",
// the impl ([$A,$B,$C]) not the receiver type ([$C]).
let impl_polytype = self.impl_self_ty(self.span, impl_def_id);
let impl_trait_ref =
- self.instantiate_type_scheme(
- self.span,
- impl_polytype.substs,
- &self.tcx.impl_trait_ref(impl_def_id).unwrap());
+ self.instantiate_type_scheme(self.span,
+ impl_polytype.substs,
+ &self.tcx.impl_trait_ref(impl_def_id).unwrap());
impl_trait_ref.substs
}
}
}
- fn extract_existential_trait_ref<R, F>(&mut self,
- self_ty: Ty<'tcx>,
- mut closure: F) -> R
+ fn extract_existential_trait_ref<R, F>(&mut self, self_ty: Ty<'tcx>, mut closure: F) -> R
where F: FnMut(&mut ConfirmContext<'a, 'gcx, 'tcx>,
Ty<'tcx>,
- ty::PolyExistentialTraitRef<'tcx>) -> R,
+ ty::PolyExistentialTraitRef<'tcx>)
+ -> R
{
// If we specified that this is an object method, then the
// self-type ought to be something that can be dereferenced to
// etc).
// FIXME: this feels, like, super dubious
- self.fcx.autoderef(self.span, self_ty)
+ self.fcx
+ .autoderef(self.span, self_ty)
.filter_map(|(ty, _)| {
match ty.sty {
ty::TyTrait(ref data) => Some(closure(self, ty, data.principal)),
})
.next()
.unwrap_or_else(|| {
- span_bug!(
- self.span,
- "self-type `{}` for ObjectPick never dereferenced to an object",
- self_ty)
+ span_bug!(self.span,
+ "self-type `{}` for ObjectPick never dereferenced to an object",
+ self_ty)
})
}
pick: &probe::Pick<'tcx>,
mut supplied_method_types: Vec<Ty<'tcx>>,
substs: &Substs<'tcx>)
- -> &'tcx Substs<'tcx>
- {
+ -> &'tcx Substs<'tcx> {
// Determine the values for the generic parameters of the method.
// If they were not explicitly supplied, just construct fresh
// variables.
if num_supplied_types > 0 && num_supplied_types != num_method_types {
if num_method_types == 0 {
- span_err!(self.tcx.sess, self.span, E0035,
- "does not take type parameters");
+ struct_span_err!(self.tcx.sess,
+ self.span,
+ E0035,
+ "does not take type parameters")
+ .span_label(self.span, &"called with unneeded type parameters")
+ .emit();
} else {
- span_err!(self.tcx.sess, self.span, E0036,
- "incorrect number of type parameters given for this method: \
- expected {}, found {}",
- num_method_types, num_supplied_types);
+ struct_span_err!(self.tcx.sess,
+ self.span,
+ E0036,
+ "incorrect number of type parameters given for this method: \
+ expected {}, found {}",
+ num_method_types,
+ num_supplied_types)
+ .span_label(self.span,
+ &format!("Passed {} type argument{}, expected {}",
+ num_supplied_types,
+ if num_supplied_types != 1 { "s" } else { "" },
+ num_method_types))
+ .emit();
}
supplied_method_types = vec![self.tcx.types.err; num_method_types];
}
//
// FIXME -- permit users to manually specify lifetimes
let supplied_start = substs.params().len() + method.generics.regions.len();
- Substs::for_item(self.tcx, method.def_id, |def, _| {
+ Substs::for_item(self.tcx,
+ method.def_id,
+ |def, _| {
let i = def.index as usize;
if i < substs.params().len() {
substs.region_at(i)
} else {
self.region_var_for_def(self.span, def)
}
- }, |def, cur_substs| {
+ },
+ |def, cur_substs| {
let i = def.index as usize;
if i < substs.params().len() {
substs.type_at(i)
})
}
- fn unify_receivers(&mut self,
- self_ty: Ty<'tcx>,
- method_self_ty: Ty<'tcx>)
- {
- match self.sub_types(false, TypeOrigin::Misc(self.span),
- self_ty, method_self_ty) {
+ fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) {
+ match self.sub_types(false, TypeOrigin::Misc(self.span), self_ty, method_self_ty) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
}
Err(_) => {
- span_bug!(
- self.span,
- "{} was a subtype of {} but now is not?",
- self_ty, method_self_ty);
+ span_bug!(self.span,
+ "{} was a subtype of {} but now is not?",
+ self_ty,
+ method_self_ty);
}
}
}
fn instantiate_method_sig(&mut self,
pick: &probe::Pick<'tcx>,
all_substs: &'tcx Substs<'tcx>)
- -> InstantiatedMethodSig<'tcx>
- {
+ -> InstantiatedMethodSig<'tcx> {
debug!("instantiate_method_sig(pick={:?}, all_substs={:?})",
pick,
all_substs);
// Instantiate the bounds on the method with the
// type/early-bound-regions substitutions performed. There can
// be no late-bound regions appearing here.
- let method_predicates = pick.item.as_opt_method().unwrap()
- .predicates.instantiate(self.tcx, all_substs);
- let method_predicates = self.normalize_associated_types_in(self.span,
- &method_predicates);
+ let method_predicates = pick.item
+ .as_opt_method()
+ .unwrap()
+ .predicates
+ .instantiate(self.tcx, all_substs);
+ let method_predicates = self.normalize_associated_types_in(self.span, &method_predicates);
- debug!("method_predicates after subst = {:?}",
- method_predicates);
+ debug!("method_predicates after subst = {:?}", method_predicates);
// Instantiate late-bound regions and substitute the trait
// parameters into the method type to get the actual method type.
// NB: Instantiate late-bound regions first so that
// `instantiate_type_scheme` can normalize associated types that
// may reference those regions.
- let method_sig = self.replace_late_bound_regions_with_fresh_var(
- &pick.item.as_opt_method().unwrap().fty.sig);
+ let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.item
+ .as_opt_method()
+ .unwrap()
+ .fty
+ .sig);
debug!("late-bound lifetimes from method instantiated, method_sig={:?}",
method_sig);
let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig);
- debug!("type scheme substituted, method_sig={:?}",
- method_sig);
+ debug!("type scheme substituted, method_sig={:?}", method_sig);
InstantiatedMethodSig {
method_sig: method_sig,
all_substs,
method_predicates);
- self.add_obligations_for_parameters(
- traits::ObligationCause::misc(self.span, self.body_id),
- method_predicates);
+ self.add_obligations_for_parameters(traits::ObligationCause::misc(self.span, self.body_id),
+ method_predicates);
// this is a projection from a trait reference, so we have to
// make sure that the trait reference inputs are well-formed.
// Fix up autoderefs and derefs.
for (i, &expr) in exprs.iter().rev().enumerate() {
+ debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?}", i, expr);
+
// Count autoderefs.
- let autoderef_count = match self.tables
- .borrow()
- .adjustments
- .get(&expr.id) {
- Some(&AdjustDerefRef(ref adj)) => adj.autoderefs,
- Some(_) | None => 0,
- };
-
- debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?} \
- autoderef_count={}",
- i, expr, autoderef_count);
-
- if autoderef_count > 0 {
- let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id));
- autoderef.nth(autoderef_count).unwrap_or_else(|| {
- span_bug!(expr.span, "expr was deref-able {} times but now isn't?",
- autoderef_count);
- });
- autoderef.finalize(PreferMutLvalue, Some(expr));
+ let adjustment = self.tables.borrow().adjustments.get(&expr.id).cloned();
+ match adjustment {
+ Some(Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) => {
+ 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, Some(expr));
+ }
+ }
+ Some(_) | None => {}
}
// Don't retry the first one or we might infinite loop!
// ought to recode this routine so it doesn't
// (ab)use the normal type checking paths.
let adj = self.tables.borrow().adjustments.get(&base_expr.id).cloned();
- let (autoderefs, unsize) = match adj {
- Some(AdjustDerefRef(adr)) => match adr.autoref {
- None => {
- assert!(adr.unsize.is_none());
- (adr.autoderefs, None)
+ let (autoderefs, unsize, adjusted_base_ty) = match adj {
+ Some(Adjustment {
+ kind: Adjust::DerefRef { autoderefs, autoref, unsize },
+ target
+ }) => {
+ match autoref {
+ None => {
+ assert!(!unsize);
+ }
+ Some(AutoBorrow::Ref(..)) => {}
+ Some(_) => {
+ span_bug!(base_expr.span,
+ "unexpected adjustment autoref {:?}",
+ adj);
+ }
}
- Some(AutoPtr(..)) => {
- (adr.autoderefs, adr.unsize.map(|target| {
- target.builtin_deref(false, NoPreference)
- .expect("fixup: AutoPtr is not &T").ty
- }))
- }
- Some(_) => {
- span_bug!(
- base_expr.span,
- "unexpected adjustment autoref {:?}",
- adr);
- }
- },
- None => (0, None),
+
+ (autoderefs, unsize, if unsize {
+ target.builtin_deref(false, NoPreference)
+ .expect("fixup: AutoBorrow::Ref is not &T")
+ .ty
+ } else {
+ let ty = self.node_ty(base_expr.id);
+ let mut ty = self.shallow_resolve(ty);
+ let mut method_type = |method_call: ty::MethodCall| {
+ self.tables.borrow().method_map.get(&method_call).map(|m| {
+ self.resolve_type_vars_if_possible(&m.ty)
+ })
+ };
+
+ if !ty.references_error() {
+ for i in 0..autoderefs {
+ ty = ty.adjust_for_autoderef(self.tcx,
+ base_expr.id,
+ base_expr.span,
+ i as u32,
+ &mut method_type);
+ }
+ }
+
+ ty
+ })
+ }
+ None => (0, false, self.node_ty(base_expr.id)),
Some(_) => {
- span_bug!(
- base_expr.span,
- "unexpected adjustment type");
+ span_bug!(base_expr.span, "unexpected adjustment type");
}
};
- let (adjusted_base_ty, unsize) = if let Some(target) = unsize {
- (target, true)
- } else {
- (self.adjust_expr_ty(base_expr,
- Some(&AdjustDerefRef(AutoDerefRef {
- autoderefs: autoderefs,
- autoref: None,
- unsize: None
- }))), false)
- };
let index_expr_ty = self.node_ty(index_expr.id);
- let result = self.try_index_step(
- ty::MethodCall::expr(expr.id),
- expr,
- &base_expr,
- adjusted_base_ty,
- autoderefs,
- unsize,
- PreferMutLvalue,
- index_expr_ty);
+ let result = self.try_index_step(ty::MethodCall::expr(expr.id),
+ expr,
+ &base_expr,
+ adjusted_base_ty,
+ autoderefs,
+ unsize,
+ PreferMutLvalue,
+ index_expr_ty);
if let Some((input_ty, return_ty)) = result {
self.demand_suptype(index_expr.span, input_ty, index_expr_ty);
let method_call = ty::MethodCall::expr(expr.id);
if self.tables.borrow().method_map.contains_key(&method_call) {
let method = self.try_overloaded_deref(expr.span,
- Some(&base_expr),
- self.node_ty(base_expr.id),
- PreferMutLvalue);
+ Some(&base_expr),
+ self.node_ty(base_expr.id),
+ PreferMutLvalue);
let method = method.expect("re-trying deref failed");
self.tables.borrow_mut().method_map.insert(method_call, method);
}
fn upcast(&mut self,
source_trait_ref: ty::PolyTraitRef<'tcx>,
target_trait_def_id: DefId)
- -> ty::PolyTraitRef<'tcx>
- {
- let upcast_trait_refs = self.tcx.upcast_choices(source_trait_ref.clone(),
- target_trait_def_id);
+ -> ty::PolyTraitRef<'tcx> {
+ let upcast_trait_refs = self.tcx
+ .upcast_choices(source_trait_ref.clone(), target_trait_def_id);
// must be exactly one trait ref or we'd get an ambig error etc
if upcast_trait_refs.len() != 1 {
- span_bug!(
- self.span,
- "cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
- source_trait_ref,
- target_trait_def_id,
- upcast_trait_refs);
+ span_bug!(self.span,
+ "cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
+ source_trait_ref,
+ target_trait_def_id,
+ upcast_trait_refs);
}
upcast_trait_refs.into_iter().next().unwrap()
}
fn replace_late_bound_regions_with_fresh_var<T>(&self, value: &ty::Binder<T>) -> T
- where T : TypeFoldable<'tcx>
+ where T: TypeFoldable<'tcx>
{
- self.fcx.replace_late_bound_regions_with_fresh_var(
- self.span, infer::FnCall, value).0
+ self.fcx
+ .replace_late_bound_regions_with_fresh_var(self.span, infer::FnCall, value)
+ .0
}
}