summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_typeck/src/method/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_typeck/src/method/mod.rs')
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs169
1 files changed, 88 insertions, 81 deletions
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index a1278edef..a2ca5c3b7 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -10,6 +10,7 @@ mod suggest;
pub use self::suggest::SelfSource;
pub use self::MethodError::*;
+use crate::errors::OpMethodGenericParams;
use crate::{Expectation, FnCtxt};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diagnostic};
@@ -19,11 +20,11 @@ use rustc_hir::def_id::DefId;
use rustc_infer::infer::{self, InferOk};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
-use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable};
+use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitable};
use rustc_span::symbol::Ident;
use rustc_span::Span;
-use rustc_trait_selection::traits;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::traits::{self, NormalizeExt};
use self::probe::{IsSuggestion, ProbeScope};
@@ -55,8 +56,7 @@ pub enum MethodError<'tcx> {
// not-in-scope traits which may work.
PrivateMatch(DefKind, DefId, Vec<DefId>),
- // Found a `Self: Sized` bound where `Self` is a trait object, also the caller may have
- // forgotten to import a trait.
+ // Found a `Self: Sized` bound where `Self` is a trait object.
IllegalSizedBound(Vec<DefId>, bool, Span),
// Found a match, but the return type is wrong
@@ -93,17 +93,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
call_expr_id: hir::HirId,
allow_private: bool,
) -> bool {
- let mode = probe::Mode::MethodCall;
match self.probe_for_name(
- method_name.span,
- mode,
+ probe::Mode::MethodCall,
method_name,
IsSuggestion(false),
self_ty,
call_expr_id,
ProbeScope::TraitsInScope,
) {
- Ok(..) => true,
+ Ok(pick) => {
+ pick.maybe_emit_unstable_name_collision_hint(
+ self.tcx,
+ method_name.span,
+ call_expr_id,
+ );
+ true
+ }
Err(NoMatch(..)) => false,
Err(Ambiguity(..)) => true,
Err(PrivateMatch(..)) => allow_private,
@@ -125,10 +130,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
let params = self
.probe_for_name(
- method_name.span,
probe::Mode::MethodCall,
method_name,
- IsSuggestion(false),
+ IsSuggestion(true),
self_ty,
call_expr.hir_id,
ProbeScope::TraitsInScope,
@@ -175,7 +179,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
args: &'tcx [hir::Expr<'tcx>],
) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
let pick =
- self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
+ self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args);
@@ -200,13 +204,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.mk_ref(*region, ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() });
// We probe again to see if there might be a borrow mutability discrepancy.
match self.lookup_probe(
- span,
segment.ident,
trait_type,
call_expr,
ProbeScope::TraitsInScope,
) {
- Ok(ref new_pick) if *new_pick != pick => {
+ Ok(ref new_pick) if pick.differs_from(new_pick) => {
needs_mut = true;
}
_ => {}
@@ -214,29 +217,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
// We probe again, taking all traits into account (not only those in scope).
- let mut candidates = match self.lookup_probe(
- span,
- segment.ident,
- self_ty,
- call_expr,
- ProbeScope::AllTraits,
- ) {
- // If we find a different result the caller probably forgot to import a trait.
- Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container_id(self.tcx)],
- Err(Ambiguity(ref sources)) => sources
- .iter()
- .filter_map(|source| {
- match *source {
- // Note: this cannot come from an inherent impl,
- // because the first probing succeeded.
- CandidateSource::Impl(def) => self.tcx.trait_id_of_impl(def),
- CandidateSource::Trait(_) => None,
- }
- })
- .collect(),
- _ => Vec::new(),
- };
- candidates.retain(|candidate| *candidate != self.tcx.parent(result.callee.def_id));
+ let candidates =
+ match self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::AllTraits) {
+ // If we find a different result the caller probably forgot to import a trait.
+ Ok(ref new_pick) if pick.differs_from(new_pick) => {
+ vec![new_pick.item.container_id(self.tcx)]
+ }
+ Err(Ambiguity(ref sources)) => sources
+ .iter()
+ .filter_map(|source| {
+ match *source {
+ // Note: this cannot come from an inherent impl,
+ // because the first probing succeeded.
+ CandidateSource::Impl(def) => self.tcx.trait_id_of_impl(def),
+ CandidateSource::Trait(_) => None,
+ }
+ })
+ .collect(),
+ _ => Vec::new(),
+ };
return Err(IllegalSizedBound(candidates, needs_mut, span));
}
@@ -247,23 +246,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(level = "debug", skip(self, call_expr))]
pub fn lookup_probe(
&self,
- span: Span,
method_name: Ident,
self_ty: Ty<'tcx>,
call_expr: &'tcx hir::Expr<'tcx>,
scope: ProbeScope,
) -> probe::PickResult<'tcx> {
- let mode = probe::Mode::MethodCall;
- let self_ty = self.resolve_vars_if_possible(self_ty);
- self.probe_for_name(
- span,
- mode,
+ let pick = self.probe_for_name(
+ probe::Mode::MethodCall,
method_name,
IsSuggestion(false),
self_ty,
call_expr.hir_id,
scope,
- )
+ )?;
+ pick.maybe_emit_unstable_name_collision_hint(self.tcx, method_name.span, call_expr.hir_id);
+ Ok(pick)
}
pub(super) fn obligation_for_method(
@@ -295,10 +292,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let poly_trait_ref = ty::Binder::dummy(trait_ref);
(
traits::Obligation::misc(
+ self.tcx,
span,
self.body_id,
self.param_env,
- poly_trait_ref.without_const().to_predicate(self.tcx),
+ poly_trait_ref.without_const(),
),
substs,
)
@@ -337,6 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(
traits::Obligation::new(
+ self.tcx,
traits::ObligationCause::new(
span,
self.body_id,
@@ -348,7 +347,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},
),
self.param_env,
- poly_trait_ref.without_const().to_predicate(self.tcx),
+ poly_trait_ref,
),
substs,
)
@@ -444,7 +443,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let def_id = method_item.def_id;
let generics = tcx.generics_of(def_id);
- assert_eq!(generics.params.len(), 0);
+
+ if generics.params.len() != 0 {
+ tcx.sess.emit_fatal(OpMethodGenericParams {
+ span: tcx.def_span(method_item.def_id),
+ method_name: m_name.to_string(),
+ });
+ }
debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
let mut obligations = vec![];
@@ -459,11 +464,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let fn_sig = fn_sig.subst(self.tcx, substs);
let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig);
- let InferOk { value, obligations: o } = if is_op {
- self.normalize_op_associated_types_in_as_infer_ok(span, fn_sig, opt_input_expr)
+ let cause = if is_op {
+ ObligationCause::new(
+ span,
+ self.body_id,
+ traits::BinOp {
+ rhs_span: opt_input_expr.map(|expr| expr.span),
+ is_lit: opt_input_expr
+ .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
+ output_ty: None,
+ },
+ )
} else {
- self.normalize_associated_types_in_as_infer_ok(span, fn_sig)
+ traits::ObligationCause::misc(span, self.body_id)
};
+
+ let InferOk { value, obligations: o } = self.at(&cause, self.param_env).normalize(fn_sig);
let fn_sig = {
obligations.extend(o);
value
@@ -479,11 +495,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// any late-bound regions appearing in its bounds.
let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs);
- let InferOk { value, obligations: o } = if is_op {
- self.normalize_op_associated_types_in_as_infer_ok(span, bounds, opt_input_expr)
- } else {
- self.normalize_associated_types_in_as_infer_ok(span, bounds)
- };
+ let InferOk { value, obligations: o } = self.at(&cause, self.param_env).normalize(bounds);
let bounds = {
obligations.extend(o);
value
@@ -491,20 +503,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
assert!(!bounds.has_escaping_bound_vars());
- let cause = if is_op {
- ObligationCause::new(
- span,
- self.body_id,
- traits::BinOp {
- rhs_span: opt_input_expr.map(|expr| expr.span),
- is_lit: opt_input_expr
- .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
- output_ty: None,
- },
- )
- } else {
- traits::ObligationCause::misc(span, self.body_id)
- };
let predicates_cause = cause.clone();
obligations.extend(traits::predicates_for_generics(
move |_, _| predicates_cause.clone(),
@@ -519,9 +517,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
method_ty, obligation
);
obligations.push(traits::Obligation::new(
+ tcx,
cause,
self.param_env,
- ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())).to_predicate(tcx),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())),
));
let callee = MethodCallee { def_id, substs, sig: fn_sig };
@@ -559,6 +558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tcx = self.tcx;
// Check if we have an enum variant.
+ let mut struct_variant = None;
if let ty::Adt(adt_def, _) = self_ty.kind() {
if adt_def.is_enum() {
let variant_def = adt_def
@@ -566,29 +566,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.iter()
.find(|vd| tcx.hygienic_eq(method_name, vd.ident(tcx), adt_def.did()));
if let Some(variant_def) = variant_def {
- // Braced variants generate unusable names in value namespace (reserved for
- // possible future use), so variants resolved as associated items may refer to
- // them as well. It's ok to use the variant's id as a ctor id since an
- // error will be reported on any use of such resolution anyway.
- let ctor_def_id = variant_def.ctor_def_id.unwrap_or(variant_def.def_id);
- tcx.check_stability(ctor_def_id, Some(expr_id), span, Some(method_name.span));
- return Ok((
- DefKind::Ctor(CtorOf::Variant, variant_def.ctor_kind),
- ctor_def_id,
- ));
+ if let Some((ctor_kind, ctor_def_id)) = variant_def.ctor {
+ tcx.check_stability(
+ ctor_def_id,
+ Some(expr_id),
+ span,
+ Some(method_name.span),
+ );
+ return Ok((DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id));
+ } else {
+ struct_variant = Some((DefKind::Variant, variant_def.def_id));
+ }
}
}
}
let pick = self.probe_for_name(
- span,
probe::Mode::Path,
method_name,
IsSuggestion(false),
self_ty,
expr_id,
ProbeScope::TraitsInScope,
- )?;
+ );
+ let pick = match (pick, struct_variant) {
+ // Fall back to a resolution that will produce an error later.
+ (Err(_), Some(res)) => return Ok(res),
+ (pick, _) => pick?,
+ };
+
+ pick.maybe_emit_unstable_name_collision_hint(self.tcx, span, expr_id);
self.lint_fully_qualified_call_from_2018(
span,