summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_typeck/src/demand.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs (renamed from compiler/rustc_typeck/src/check/demand.rs)135
1 files changed, 87 insertions, 48 deletions
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index e1d55ff82..16febfc46 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -1,21 +1,20 @@
-use crate::check::FnCtxt;
-use rustc_infer::infer::InferOk;
-use rustc_middle::middle::stability::EvalResult;
-use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::ObligationCause;
-
+use crate::FnCtxt;
use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{is_range_literal, Node};
+use rustc_infer::infer::InferOk;
use rustc_middle::lint::in_external_macro;
+use rustc_middle::middle::stability::EvalResult;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{BytePos, Span};
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::ObligationCause;
use super::method::probe;
@@ -32,17 +31,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
error: Option<TypeError<'tcx>>,
) {
self.annotate_expected_due_to_let_ty(err, expr, error);
- self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
- self.suggest_compatible_variants(err, expr, expected, expr_ty);
- self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty);
- if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
- return;
- }
- self.suggest_no_capture_closure(err, expected, expr_ty);
- self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
- self.suggest_missing_parentheses(err, expr);
- self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected);
- self.suggest_copied_or_cloned(err, expr, expr_ty, expected);
+
+ // Use `||` to give these suggestions a precedence
+ let _ = self.suggest_missing_parentheses(err, expr)
+ || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr)
+ || self.suggest_compatible_variants(err, expr, expected, expr_ty)
+ || self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty)
+ || self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty)
+ || self.suggest_no_capture_closure(err, expected, expr_ty)
+ || self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty)
+ || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
+ || self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
+ || self.suggest_into(err, expr, expr_ty, expected);
+
self.note_type_is_not_clone(err, expected, expr_ty, expr);
self.note_need_for_fn_pointer(err, expected, expr_ty);
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
@@ -77,7 +78,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.register_predicates(obligations);
None
}
- Err(e) => Some(self.report_mismatched_types(&cause, expected, actual, e)),
+ Err(e) => Some(self.err_ctxt().report_mismatched_types(&cause, expected, actual, e)),
}
}
@@ -107,7 +108,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.register_predicates(obligations);
None
}
- Err(e) => Some(self.report_mismatched_types(cause, expected, actual, e)),
+ Err(e) => Some(self.err_ctxt().report_mismatched_types(cause, expected, actual, e)),
}
}
@@ -151,7 +152,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let expr = expr.peel_drop_temps();
let cause = self.misc(expr.span);
let expr_ty = self.resolve_vars_with_obligations(checked_ty);
- let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e.clone());
+ let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e.clone());
let is_insufficiently_polymorphic =
matches!(e, TypeError::RegionsInsufficientlyPolymorphic(..));
@@ -286,7 +287,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
expected: Ty<'tcx>,
expr_ty: Ty<'tcx>,
- ) {
+ ) -> bool {
if let ty::Adt(expected_adt, substs) = expected.kind() {
if let hir::ExprKind::Field(base, ident) = expr.kind {
let base_ty = self.typeck_results.borrow().expr_ty(base);
@@ -299,7 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"",
Applicability::MaybeIncorrect,
);
- return
+ return true;
}
}
@@ -338,7 +339,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) {
vec!["None", "Some(())"]
} else {
- return;
+ return false;
};
if let Some(indent) =
self.tcx.sess.source_map().indentation_before(span.shrink_to_lo())
@@ -358,7 +359,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MaybeIncorrect,
);
}
- return;
+ return true;
}
}
}
@@ -375,7 +376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let field_is_local = sole_field.did.is_local();
let field_is_accessible =
- sole_field.vis.is_accessible_from(expr.hir_id.owner, self.tcx)
+ sole_field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx)
// Skip suggestions for unstable public fields (for example `Pin::pointer`)
&& matches!(self.tcx.eval_stability(sole_field.did, None, expr.span, None), EvalResult::Allow | EvalResult::Unmarked);
@@ -417,6 +418,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir::def::CtorKind::Const => unreachable!(),
};
+ // Suggest constructor as deep into the block tree as possible.
+ // This fixes https://github.com/rust-lang/rust/issues/101065,
+ // and also just helps make the most minimal suggestions.
+ let mut expr = expr;
+ while let hir::ExprKind::Block(block, _) = &expr.kind
+ && let Some(expr_) = &block.expr
+ {
+ expr = expr_
+ }
+
vec![
(expr.span.shrink_to_lo(), format!("{prefix}{variant}{open}")),
(expr.span.shrink_to_hi(), close.to_owned()),
@@ -435,6 +446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggestions_for(&**variant, *ctor_kind, *field_name),
Applicability::MaybeIncorrect,
);
+ return true;
}
_ => {
// More than one matching variant.
@@ -450,9 +462,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
),
Applicability::MaybeIncorrect,
);
+ return true;
}
}
}
+
+ false
}
fn suggest_non_zero_new_unwrap(
@@ -461,19 +476,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
expected: Ty<'tcx>,
expr_ty: Ty<'tcx>,
- ) {
+ ) -> bool {
let tcx = self.tcx;
let (adt, unwrap) = match expected.kind() {
// In case Option<NonZero*> is wanted, but * is provided, suggest calling new
ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
// Unwrap option
- let ty::Adt(adt, _) = substs.type_at(0).kind() else { return };
+ let ty::Adt(adt, _) = substs.type_at(0).kind() else { return false; };
(adt, "")
}
// In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types
ty::Adt(adt, _) => (adt, ".unwrap()"),
- _ => return,
+ _ => return false,
};
let map = [
@@ -492,7 +507,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some((s, _)) = map
.iter()
.find(|&&(s, t)| self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t))
- else { return };
+ else { return false; };
let path = self.tcx.def_path_str(adt.non_enum_variant().def_id);
@@ -504,6 +519,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
],
Applicability::MaybeIncorrect,
);
+
+ true
}
pub fn get_conversion_methods(
@@ -513,24 +530,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
checked_ty: Ty<'tcx>,
hir_id: hir::HirId,
) -> Vec<AssocItem> {
- let mut methods =
- self.probe_for_return_type(span, probe::Mode::MethodCall, expected, checked_ty, hir_id);
- methods.retain(|m| {
- self.has_only_self_parameter(m)
- && self
- .tcx
- // This special internal attribute is used to permit
- // "identity-like" conversion methods to be suggested here.
- //
- // FIXME (#46459 and #46460): ideally
- // `std::convert::Into::into` and `std::borrow:ToOwned` would
- // also be `#[rustc_conversion_suggestion]`, if not for
- // method-probing false-positives and -negatives (respectively).
- //
- // FIXME? Other potential candidate methods: `as_ref` and
- // `as_mut`?
- .has_attr(m.def_id, sym::rustc_conversion_suggestion)
- });
+ let methods = self.probe_for_return_type(
+ span,
+ probe::Mode::MethodCall,
+ expected,
+ checked_ty,
+ hir_id,
+ |m| {
+ self.has_only_self_parameter(m)
+ && self
+ .tcx
+ // This special internal attribute is used to permit
+ // "identity-like" conversion methods to be suggested here.
+ //
+ // FIXME (#46459 and #46460): ideally
+ // `std::convert::Into::into` and `std::borrow:ToOwned` would
+ // also be `#[rustc_conversion_suggestion]`, if not for
+ // method-probing false-positives and -negatives (respectively).
+ //
+ // FIXME? Other potential candidate methods: `as_ref` and
+ // `as_mut`?
+ .has_attr(m.def_id, sym::rustc_conversion_suggestion)
+ },
+ );
methods
}
@@ -697,7 +719,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
- ) -> Option<(Span, String, String, Applicability, bool /* verbose */)> {
+ ) -> Option<(
+ Span,
+ String,
+ String,
+ Applicability,
+ bool, /* verbose */
+ bool, /* suggest `&` or `&mut` type annotation */
+ )> {
let sess = self.sess();
let sp = expr.span;
@@ -729,6 +758,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
String::new(),
Applicability::MachineApplicable,
true,
+ false,
));
}
}
@@ -743,6 +773,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"b".to_string(),
Applicability::MachineApplicable,
true,
+ false,
));
}
}
@@ -800,6 +831,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
sugg.2,
Applicability::MachineApplicable,
false,
+ false,
));
}
@@ -827,6 +859,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("{prefix}&mut {sugg_expr}"),
Applicability::MachineApplicable,
false,
+ false,
),
hir::Mutability::Not => (
sp,
@@ -834,6 +867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("{prefix}&{sugg_expr}"),
Applicability::MachineApplicable,
false,
+ false,
),
});
}
@@ -863,6 +897,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
String::new(),
Applicability::MachineApplicable,
true,
+ true
));
}
return None;
@@ -876,6 +911,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
String::new(),
Applicability::MachineApplicable,
true,
+ true,
));
}
}
@@ -942,6 +978,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
src,
applicability,
true,
+ false,
));
}
}
@@ -982,6 +1019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MachineApplicable
},
true,
+ false,
));
}
@@ -1033,6 +1071,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggestion,
Applicability::MachineApplicable,
true,
+ false,
));
}
}