Auto merge of #106760 - compiler-errors:rollup-0bogyco, r=compiler-errors
Rollup of 8 pull requests Successful merges: - #103236 (doc: rewrite doc for signed int::{carrying_add,borrowing_sub}) - #103800 (Stabilize `::{core,std}::pin::pin!`) - #106097 (Migrate mir_build diagnostics 2 of 3) - #106170 (Move autoderef to `rustc_hir_analysis`) - #106323 (Stabilize f16c_target_feature) - #106360 (Tweak E0277 `&`-removal suggestions) - #106524 (Label `struct/enum constructor` instead of `fn item`, mention that it should be called on type mismatch) - #106739 (Remove `<dyn AstConv<'tcx>>::fun(c, ...)` calls in favour of `c.astconv().fun(...)`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
606c390725
108 changed files with 1713 additions and 1422 deletions
|
@ -187,7 +187,7 @@ const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
|||
("bmi2", None),
|
||||
("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)),
|
||||
("ermsb", Some(sym::ermsb_target_feature)),
|
||||
("f16c", Some(sym::f16c_target_feature)),
|
||||
("f16c", None),
|
||||
("fma", None),
|
||||
("fxsr", None),
|
||||
("gfni", Some(sym::avx512_target_feature)),
|
||||
|
@ -396,7 +396,6 @@ pub fn from_target_feature(
|
|||
Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature,
|
||||
Some(sym::movbe_target_feature) => rust_features.movbe_target_feature,
|
||||
Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
|
||||
Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
|
||||
Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
|
||||
Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
|
||||
Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
|
||||
|
|
|
@ -120,3 +120,7 @@ hir_analysis_self_in_impl_self =
|
|||
|
||||
hir_analysis_linkage_type =
|
||||
invalid type for variable with `#[linkage]` attribute
|
||||
|
||||
hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}`
|
||||
.label = deref recursion limit reached
|
||||
.help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
|
||||
|
|
|
@ -303,3 +303,64 @@ mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once a
|
|||
.mutable_borrow = another mutable borrow, by `{$name_mut}`, occurs here
|
||||
.immutable_borrow = also borrowed as immutable, by `{$name_immut}`, here
|
||||
.moved = also moved into `{$name_moved}` here
|
||||
|
||||
mir_build_union_pattern = cannot use unions in constant patterns
|
||||
|
||||
mir_build_type_not_structural =
|
||||
to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
|
||||
mir_build_unsized_pattern = cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns
|
||||
|
||||
mir_build_invalid_pattern = `{$non_sm_ty}` cannot be used in patterns
|
||||
|
||||
mir_build_float_pattern = floating-point types cannot be used in patterns
|
||||
|
||||
mir_build_pointer_pattern = function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
|
||||
|
||||
mir_build_indirect_structural_match =
|
||||
to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
|
||||
mir_build_nontrivial_structural_match =
|
||||
to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
|
||||
mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpoints
|
||||
.range = ... with this range
|
||||
.note = you likely meant to write mutually exclusive ranges
|
||||
|
||||
mir_build_non_exhaustive_omitted_pattern = some variants are not matched explicitly
|
||||
.help = ensure that all variants are matched explicitly by adding the suggested match arms
|
||||
.note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found
|
||||
|
||||
mir_build_uncovered = {$count ->
|
||||
[1] pattern `{$witness_1}`
|
||||
[2] patterns `{$witness_1}` and `{$witness_2}`
|
||||
[3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}`
|
||||
*[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
|
||||
} not covered
|
||||
|
||||
mir_build_pattern_not_covered = refutable pattern in {$origin}
|
||||
.pattern_ty = the matched value is of type `{$pattern_ty}`
|
||||
|
||||
mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
|
||||
|
||||
mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
|
||||
|
||||
mir_build_res_defined_here = {$res} defined here
|
||||
|
||||
mir_build_adt_defined_here = `{$ty}` defined here
|
||||
|
||||
mir_build_variant_defined_here = not covered
|
||||
|
||||
mir_build_interpreted_as_const = introduce a variable instead
|
||||
|
||||
mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as {$article} {$res} pattern, not a new variable
|
||||
|
||||
mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count ->
|
||||
[one] variant that isn't
|
||||
*[other] variants that aren't
|
||||
} matched
|
||||
|
||||
mir_build_suggest_let_else = you might want to use `let else` to handle the {$count ->
|
||||
[one] variant that isn't
|
||||
*[other] variants that aren't
|
||||
} matched
|
||||
|
|
|
@ -2,10 +2,6 @@ trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entri
|
|||
|
||||
trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated}
|
||||
|
||||
trait_selection_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}`
|
||||
.label = deref recursion limit reached
|
||||
.help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
|
||||
|
||||
trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]`
|
||||
.label = empty on-clause here
|
||||
|
||||
|
|
|
@ -161,6 +161,8 @@ declare_features! (
|
|||
(accepted, extern_crate_self, "1.34.0", Some(56409), None),
|
||||
/// Allows access to crate names passed via `--extern` through prelude.
|
||||
(accepted, extern_prelude, "1.30.0", Some(44660), None),
|
||||
/// Allows using F16C intrinsics from `core::arch::{x86, x86_64}`.
|
||||
(accepted, f16c_target_feature, "CURRENT_RUSTC_VERSION", Some(44839), None),
|
||||
/// Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
|
||||
(accepted, field_init_shorthand, "1.17.0", Some(37340), None),
|
||||
/// Allows `#[must_use]` on functions, and introduces must-use operators (RFC 1940).
|
||||
|
|
|
@ -254,7 +254,6 @@ declare_features! (
|
|||
(active, bpf_target_feature, "1.54.0", Some(44839), None),
|
||||
(active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None),
|
||||
(active, ermsb_target_feature, "1.49.0", Some(44839), None),
|
||||
(active, f16c_target_feature, "1.36.0", Some(44839), None),
|
||||
(active, hexagon_target_feature, "1.27.0", Some(44839), None),
|
||||
(active, mips_target_feature, "1.27.0", Some(44839), None),
|
||||
(active, movbe_target_feature, "1.34.0", Some(44839), None),
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,8 +3,11 @@
|
|||
//! instance of `AstConv`.
|
||||
|
||||
mod errors;
|
||||
mod generics;
|
||||
pub mod generics;
|
||||
|
||||
use crate::astconv::generics::{
|
||||
check_generic_arg_count, create_substs_for_generic_args, prohibit_assoc_ty_binding,
|
||||
};
|
||||
use crate::bounds::Bounds;
|
||||
use crate::collect::HirPlaceholderCollector;
|
||||
use crate::errors::{
|
||||
|
@ -120,6 +123,13 @@ pub trait AstConv<'tcx> {
|
|||
fn set_tainted_by_errors(&self, e: ErrorGuaranteed);
|
||||
|
||||
fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span);
|
||||
|
||||
fn astconv(&self) -> &dyn AstConv<'tcx>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -279,7 +289,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
ty::BoundConstness::NotConst,
|
||||
);
|
||||
if let Some(b) = item_segment.args().bindings.first() {
|
||||
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
|
||||
prohibit_assoc_ty_binding(self.tcx(), b.span);
|
||||
}
|
||||
|
||||
substs
|
||||
|
@ -349,7 +359,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
assert!(self_ty.is_none());
|
||||
}
|
||||
|
||||
let arg_count = Self::check_generic_arg_count(
|
||||
let arg_count = check_generic_arg_count(
|
||||
tcx,
|
||||
span,
|
||||
def_id,
|
||||
|
@ -524,7 +534,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
inferred_params: vec![],
|
||||
infer_args,
|
||||
};
|
||||
let substs = Self::create_substs_for_generic_args(
|
||||
let substs = create_substs_for_generic_args(
|
||||
tcx,
|
||||
def_id,
|
||||
parent_substs,
|
||||
|
@ -610,7 +620,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
);
|
||||
|
||||
if let Some(b) = item_segment.args().bindings.first() {
|
||||
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
|
||||
prohibit_assoc_ty_binding(self.tcx(), b.span);
|
||||
}
|
||||
|
||||
args
|
||||
|
@ -804,7 +814,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
constness,
|
||||
);
|
||||
if let Some(b) = trait_segment.args().bindings.first() {
|
||||
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
|
||||
prohibit_assoc_ty_binding(self.tcx(), b.span);
|
||||
}
|
||||
self.tcx().mk_trait_ref(trait_def_id, substs)
|
||||
}
|
||||
|
@ -2301,7 +2311,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
for segment in segments {
|
||||
// Only emit the first error to avoid overloading the user with error messages.
|
||||
if let Some(b) = segment.args().bindings.first() {
|
||||
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
|
||||
prohibit_assoc_ty_binding(self.tcx(), b.span);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -178,6 +178,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
|
|||
self.state.obligations
|
||||
}
|
||||
|
||||
pub fn current_obligations(&self) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||
self.state.obligations.clone()
|
||||
}
|
||||
|
||||
pub fn steps(&self) -> &[(Ty<'tcx>, AutoderefKind)] {
|
||||
&self.state.steps
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
use crate::autoderef::Autoderef;
|
||||
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
|
||||
|
||||
use hir::def::DefKind;
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
||||
|
@ -22,7 +24,6 @@ use rustc_session::parse::feature_err;
|
|||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::autoderef::Autoderef;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
|
|
|
@ -351,7 +351,7 @@ impl<'tcx> ItemCtxt<'tcx> {
|
|||
}
|
||||
|
||||
pub fn to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
|
||||
<dyn AstConv<'_>>::ast_ty_to_ty(self, ast_ty)
|
||||
self.astconv().ast_ty_to_ty(ast_ty)
|
||||
}
|
||||
|
||||
pub fn hir_id(&self) -> hir::HirId {
|
||||
|
@ -413,8 +413,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
|
|||
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
|
||||
let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
|
||||
self,
|
||||
let item_substs = self.astconv().create_substs_for_associated_item(
|
||||
span,
|
||||
item_def_id,
|
||||
item_segment,
|
||||
|
@ -1112,8 +1111,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
|
|||
tcx.hir().get_parent(hir_id)
|
||||
&& i.of_trait.is_some()
|
||||
{
|
||||
<dyn AstConv<'_>>::ty_of_fn(
|
||||
&icx,
|
||||
icx.astconv().ty_of_fn(
|
||||
hir_id,
|
||||
sig.header.unsafety,
|
||||
sig.header.abi,
|
||||
|
@ -1130,15 +1128,9 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
|
|||
kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _),
|
||||
generics,
|
||||
..
|
||||
}) => <dyn AstConv<'_>>::ty_of_fn(
|
||||
&icx,
|
||||
hir_id,
|
||||
header.unsafety,
|
||||
header.abi,
|
||||
decl,
|
||||
Some(generics),
|
||||
None,
|
||||
),
|
||||
}) => {
|
||||
icx.astconv().ty_of_fn(hir_id, header.unsafety, header.abi, decl, Some(generics), None)
|
||||
}
|
||||
|
||||
ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => {
|
||||
let abi = tcx.hir().get_foreign_abi(hir_id);
|
||||
|
@ -1244,8 +1236,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
|
|||
|
||||
ty::Binder::dummy(fn_sig)
|
||||
}
|
||||
None => <dyn AstConv<'_>>::ty_of_fn(
|
||||
icx,
|
||||
None => icx.astconv().ty_of_fn(
|
||||
hir_id,
|
||||
sig.header.unsafety,
|
||||
sig.header.abi,
|
||||
|
@ -1354,8 +1345,7 @@ fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
|
|||
match item.kind {
|
||||
hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
|
||||
let selfty = tcx.type_of(def_id);
|
||||
<dyn AstConv<'_>>::instantiate_mono_trait_ref(
|
||||
&icx,
|
||||
icx.astconv().instantiate_mono_trait_ref(
|
||||
ast_trait_ref,
|
||||
selfty,
|
||||
check_impl_constness(tcx, impl_.constness, ast_trait_ref),
|
||||
|
@ -1485,15 +1475,8 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
|
|||
hir::Unsafety::Unsafe
|
||||
};
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
|
||||
let fty = <dyn AstConv<'_>>::ty_of_fn(
|
||||
&ItemCtxt::new(tcx, def_id),
|
||||
hir_id,
|
||||
unsafety,
|
||||
abi,
|
||||
decl,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
let fty =
|
||||
ItemCtxt::new(tcx, def_id).astconv().ty_of_fn(hir_id, unsafety, abi, decl, None, None);
|
||||
|
||||
// Feature gate SIMD types in FFI, since I am not sure that the
|
||||
// ABIs are handled at all correctly. -huonw
|
||||
|
|
|
@ -26,9 +26,9 @@ fn associated_type_bounds<'tcx>(
|
|||
);
|
||||
|
||||
let icx = ItemCtxt::new(tcx, assoc_item_def_id);
|
||||
let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
|
||||
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds);
|
||||
// Associated types are implicitly sized unless a `?Sized` bound is found
|
||||
<dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, item_ty, ast_bounds, None, span);
|
||||
icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
|
||||
|
||||
let trait_def_id = tcx.parent(assoc_item_def_id);
|
||||
let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
|
||||
|
@ -70,9 +70,9 @@ fn opaque_type_bounds<'tcx>(
|
|||
};
|
||||
|
||||
let icx = ItemCtxt::new(tcx, opaque_def_id);
|
||||
let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
|
||||
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds);
|
||||
// Opaque types are implicitly sized unless a `?Sized` bound is found
|
||||
<dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, item_ty, ast_bounds, None, span);
|
||||
icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
|
||||
debug!(?bounds);
|
||||
|
||||
tcx.arena.alloc_from_iter(bounds.predicates())
|
||||
|
|
|
@ -162,8 +162,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
|||
|
||||
let mut bounds = Bounds::default();
|
||||
// Params are implicitly sized unless a `?Sized` bound is found
|
||||
<dyn AstConv<'_>>::add_implicitly_sized(
|
||||
&icx,
|
||||
icx.astconv().add_implicitly_sized(
|
||||
&mut bounds,
|
||||
param_ty,
|
||||
&[],
|
||||
|
@ -211,22 +210,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
|||
}
|
||||
|
||||
let mut bounds = Bounds::default();
|
||||
<dyn AstConv<'_>>::add_bounds(
|
||||
&icx,
|
||||
ty,
|
||||
bound_pred.bounds.iter(),
|
||||
&mut bounds,
|
||||
bound_vars,
|
||||
);
|
||||
icx.astconv().add_bounds(ty, bound_pred.bounds.iter(), &mut bounds, bound_vars);
|
||||
predicates.extend(bounds.predicates());
|
||||
}
|
||||
|
||||
hir::WherePredicate::RegionPredicate(region_pred) => {
|
||||
let r1 = <dyn AstConv<'_>>::ast_region_to_region(&icx, ®ion_pred.lifetime, None);
|
||||
let r1 = icx.astconv().ast_region_to_region(®ion_pred.lifetime, None);
|
||||
predicates.extend(region_pred.bounds.iter().map(|bound| {
|
||||
let (r2, span) = match bound {
|
||||
hir::GenericBound::Outlives(lt) => {
|
||||
(<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.ident.span)
|
||||
(icx.astconv().ast_region_to_region(lt, None), lt.ident.span)
|
||||
}
|
||||
_ => bug!(),
|
||||
};
|
||||
|
@ -279,7 +272,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
|||
debug!(?lifetimes);
|
||||
for (arg, duplicate) in std::iter::zip(lifetimes, ast_generics.params) {
|
||||
let hir::GenericArg::Lifetime(arg) = arg else { bug!() };
|
||||
let orig_region = <dyn AstConv<'_>>::ast_region_to_region(&icx, &arg, None);
|
||||
let orig_region = icx.astconv().ast_region_to_region(&arg, None);
|
||||
if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) {
|
||||
// Only early-bound regions can point to the original generic parameter.
|
||||
continue;
|
||||
|
@ -527,14 +520,9 @@ pub(super) fn super_predicates_that_define_assoc_type(
|
|||
// Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
|
||||
let self_param_ty = tcx.types.self_param;
|
||||
let superbounds1 = if let Some(assoc_name) = assoc_name {
|
||||
<dyn AstConv<'_>>::compute_bounds_that_match_assoc_type(
|
||||
&icx,
|
||||
self_param_ty,
|
||||
bounds,
|
||||
assoc_name,
|
||||
)
|
||||
icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name)
|
||||
} else {
|
||||
<dyn AstConv<'_>>::compute_bounds(&icx, self_param_ty, bounds)
|
||||
icx.astconv().compute_bounds(self_param_ty, bounds)
|
||||
};
|
||||
|
||||
let superbounds1 = superbounds1.predicates();
|
||||
|
|
|
@ -300,3 +300,15 @@ pub(crate) struct LinkageType {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[help]
|
||||
#[diag(hir_analysis_auto_deref_reached_recursion_limit, code = "E0055")]
|
||||
pub struct AutoDerefReachedRecursionLimit<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub ty: Ty<'a>,
|
||||
pub suggested_limit: rustc_session::Limit,
|
||||
pub crate_name: Symbol,
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ extern crate rustc_middle;
|
|||
pub mod check;
|
||||
|
||||
pub mod astconv;
|
||||
pub mod autoderef;
|
||||
mod bounds;
|
||||
mod check_unused;
|
||||
mod coherence;
|
||||
|
@ -544,7 +545,7 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> {
|
|||
// scope. This is derived from the enclosing item-like thing.
|
||||
let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id);
|
||||
let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
|
||||
<dyn AstConv<'_>>::ast_ty_to_ty(&item_cx, hir_ty)
|
||||
item_cx.astconv().ast_ty_to_ty(hir_ty)
|
||||
}
|
||||
|
||||
pub fn hir_trait_to_predicates<'tcx>(
|
||||
|
@ -558,8 +559,7 @@ pub fn hir_trait_to_predicates<'tcx>(
|
|||
let env_def_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
|
||||
let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
|
||||
let mut bounds = Bounds::default();
|
||||
let _ = <dyn AstConv<'_>>::instantiate_poly_trait_ref(
|
||||
&item_cx,
|
||||
let _ = &item_cx.astconv().instantiate_poly_trait_ref(
|
||||
hir_trait,
|
||||
DUMMY_SP,
|
||||
ty::BoundConstness::NotConst,
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
use super::method::MethodCallee;
|
||||
use super::{FnCtxt, PlaceOp};
|
||||
|
||||
use rustc_hir_analysis::autoderef::{Autoderef, AutoderefKind};
|
||||
use rustc_infer::infer::InferOk;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::autoderef::{Autoderef, AutoderefKind};
|
||||
|
||||
use std::iter;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed,
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{self, CtorKind, Namespace, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir_analysis::autoderef::Autoderef;
|
||||
use rustc_infer::{
|
||||
infer,
|
||||
traits::{self, Obligation},
|
||||
|
@ -25,7 +26,6 @@ use rustc_span::def_id::LocalDefId;
|
|||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::spec::abi;
|
||||
use rustc_trait_selection::autoderef::Autoderef;
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::DefIdOrName;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
|
|
|
@ -1807,7 +1807,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
// Get the return type.
|
||||
&& let hir::TyKind::OpaqueDef(..) = ty.kind
|
||||
{
|
||||
let ty = <dyn AstConv<'_>>::ast_ty_to_ty(fcx, ty);
|
||||
let ty = fcx.astconv().ast_ty_to_ty( ty);
|
||||
// Get the `impl Trait`'s `DefId`.
|
||||
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind()
|
||||
// Get the `impl Trait`'s `Item` so that we can get its trait bounds and
|
||||
|
@ -1866,7 +1866,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
|
||||
if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id)
|
||||
&& let hir::FnRetTy::Return(ty) = fn_decl.output
|
||||
&& let ty = <dyn AstConv<'_>>::ast_ty_to_ty(fcx, ty)
|
||||
&& let ty = fcx.astconv().ast_ty_to_ty( ty)
|
||||
&& let ty::Dynamic(..) = ty.kind()
|
||||
{
|
||||
return true;
|
||||
|
|
|
@ -10,6 +10,9 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{ExprKind, GenericArg, Node, QPath};
|
||||
use rustc_hir_analysis::astconv::generics::{
|
||||
check_generic_arg_count_for_call, create_substs_for_generic_args,
|
||||
};
|
||||
use rustc_hir_analysis::astconv::{
|
||||
AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
|
||||
GenericArgCountResult, IsMethodCall, PathSeg,
|
||||
|
@ -374,7 +377,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> RawTy<'tcx> {
|
||||
let t = <dyn AstConv<'_>>::ast_ty_to_ty(self, ast_t);
|
||||
let t = self.astconv().ast_ty_to_ty(ast_t);
|
||||
self.register_wf_obligation(t.into(), ast_t.span, traits::WellFormed(None));
|
||||
self.handle_raw_ty(ast_t.span, t)
|
||||
}
|
||||
|
@ -777,7 +780,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// to be object-safe.
|
||||
// We manually call `register_wf_obligation` in the success path
|
||||
// below.
|
||||
let ty = <dyn AstConv<'_>>::ast_ty_to_ty_in_path(self, qself);
|
||||
let ty = self.astconv().ast_ty_to_ty_in_path(qself);
|
||||
(self.handle_raw_ty(span, ty), qself, segment)
|
||||
}
|
||||
QPath::LangItem(..) => {
|
||||
|
@ -975,8 +978,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let path_segs = match res {
|
||||
Res::Local(_) | Res::SelfCtor(_) => vec![],
|
||||
Res::Def(kind, def_id) => <dyn AstConv<'_>>::def_ids_for_value_path_segments(
|
||||
self,
|
||||
Res::Def(kind, def_id) => self.astconv().def_ids_for_value_path_segments(
|
||||
segments,
|
||||
self_ty.map(|ty| ty.raw),
|
||||
kind,
|
||||
|
@ -1027,8 +1029,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// errors if type parameters are provided in an inappropriate place.
|
||||
|
||||
let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect();
|
||||
let generics_has_err = <dyn AstConv<'_>>::prohibit_generics(
|
||||
self,
|
||||
let generics_has_err = self.astconv().prohibit_generics(
|
||||
segments.iter().enumerate().filter_map(|(index, seg)| {
|
||||
if !generic_segs.contains(&index) || is_alias_variant_ctor {
|
||||
Some(seg)
|
||||
|
@ -1069,7 +1070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// parameter internally, but we don't allow users to specify the
|
||||
// parameter's value explicitly, so we have to do some error-
|
||||
// checking here.
|
||||
let arg_count = <dyn AstConv<'_>>::check_generic_arg_count_for_call(
|
||||
let arg_count = check_generic_arg_count_for_call(
|
||||
tcx,
|
||||
span,
|
||||
def_id,
|
||||
|
@ -1177,7 +1178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
) -> ty::GenericArg<'tcx> {
|
||||
match (¶m.kind, arg) {
|
||||
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
|
||||
<dyn AstConv<'_>>::ast_region_to_region(self.fcx, lt, Some(param)).into()
|
||||
self.fcx.astconv().ast_region_to_region(lt, Some(param)).into()
|
||||
}
|
||||
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
|
||||
self.fcx.to_ty(ty).raw.into()
|
||||
|
@ -1235,7 +1236,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
let substs_raw = self_ctor_substs.unwrap_or_else(|| {
|
||||
<dyn AstConv<'_>>::create_substs_for_generic_args(
|
||||
create_substs_for_generic_args(
|
||||
tcx,
|
||||
def_id,
|
||||
&[],
|
||||
|
|
|
@ -1664,15 +1664,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
match *qpath {
|
||||
QPath::Resolved(ref maybe_qself, ref path) => {
|
||||
let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself).raw);
|
||||
let ty = <dyn AstConv<'_>>::res_to_ty(self, self_ty, path, true);
|
||||
let ty = self.astconv().res_to_ty(self_ty, path, true);
|
||||
(path.res, self.handle_raw_ty(path_span, ty))
|
||||
}
|
||||
QPath::TypeRelative(ref qself, ref segment) => {
|
||||
let ty = self.to_ty(qself);
|
||||
|
||||
let result = <dyn AstConv<'_>>::associated_path_to_ty(
|
||||
self, hir_id, path_span, ty.raw, qself, segment, true,
|
||||
);
|
||||
let result = self
|
||||
.astconv()
|
||||
.associated_path_to_ty(hir_id, path_span, ty.raw, qself, segment, true);
|
||||
let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
|
||||
let ty = self.handle_raw_ty(path_span, ty);
|
||||
let result = result.map(|(_, kind, def_id)| (kind, def_id));
|
||||
|
|
|
@ -20,7 +20,7 @@ use rustc_middle::ty::subst::GenericArgKind;
|
|||
use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitable};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{self, Span};
|
||||
use rustc_span::{self, Span, DUMMY_SP};
|
||||
use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
@ -175,6 +175,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
fn_sig
|
||||
})
|
||||
}),
|
||||
autoderef_steps: Box::new(|ty| {
|
||||
let mut autoderef = self.autoderef(DUMMY_SP, ty).silence_errors();
|
||||
let mut steps = vec![];
|
||||
while let Some((ty, _)) = autoderef.next() {
|
||||
steps.push((ty, autoderef.current_obligations()));
|
||||
}
|
||||
steps
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -286,8 +294,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
|
|||
poly_trait_ref,
|
||||
);
|
||||
|
||||
let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
|
||||
self,
|
||||
let item_substs = self.astconv().create_substs_for_associated_item(
|
||||
span,
|
||||
item_def_id,
|
||||
item_segment,
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
|
|||
use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
|
||||
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind};
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{
|
||||
Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
|
||||
|
@ -417,10 +417,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
} else if self.suggest_else_fn_with_closure(err, expr, found, expected) {
|
||||
return true;
|
||||
} else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
|
||||
&& let ty::FnDef(def_id, ..) = &found.kind()
|
||||
&& let Some(sp) = self.tcx.hir().span_if_local(*def_id)
|
||||
&& let ty::FnDef(def_id, ..) = *found.kind()
|
||||
&& let Some(sp) = self.tcx.hir().span_if_local(def_id)
|
||||
{
|
||||
err.span_label(sp, format!("{found} defined here"));
|
||||
let name = self.tcx.item_name(def_id);
|
||||
let kind = self.tcx.def_kind(def_id);
|
||||
if let DefKind::Ctor(of, CtorKind::Fn) = kind {
|
||||
err.span_label(sp, format!("`{name}` defines {} constructor here, which should be called", match of {
|
||||
CtorOf::Struct => "a struct",
|
||||
CtorOf::Variant => "an enum variant",
|
||||
}));
|
||||
} else {
|
||||
let descr = kind.descr(def_id);
|
||||
err.span_label(sp, format!("{descr} `{name}` defined here"));
|
||||
}
|
||||
return true;
|
||||
} else if self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
|
||||
return true;
|
||||
|
@ -783,7 +793,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// are not, the expectation must have been caused by something else.
|
||||
debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
|
||||
let span = ty.span;
|
||||
let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, ty);
|
||||
let ty = self.astconv().ast_ty_to_ty(ty);
|
||||
debug!("suggest_missing_return_type: return type {:?}", ty);
|
||||
debug!("suggest_missing_return_type: expected type {:?}", ty);
|
||||
let bound_vars = self.tcx.late_bound_vars(fn_id);
|
||||
|
@ -854,7 +864,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
..
|
||||
}) => {
|
||||
// FIXME: Maybe these calls to `ast_ty_to_ty` can be removed (and the ones below)
|
||||
let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, bounded_ty);
|
||||
let ty = self.astconv().ast_ty_to_ty(bounded_ty);
|
||||
Some((ty, bounds))
|
||||
}
|
||||
_ => None,
|
||||
|
@ -892,7 +902,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let all_bounds_str = all_matching_bounds_strs.join(" + ");
|
||||
|
||||
let ty_param_used_in_fn_params = fn_parameters.iter().any(|param| {
|
||||
let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, param);
|
||||
let ty = self.astconv().ast_ty_to_ty( param);
|
||||
matches!(ty.kind(), ty::Param(fn_param_ty_param) if expected_ty_as_param == fn_param_ty_param)
|
||||
});
|
||||
|
||||
|
@ -946,7 +956,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
if let hir::FnRetTy::Return(ty) = fn_decl.output {
|
||||
let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, ty);
|
||||
let ty = self.astconv().ast_ty_to_ty(ty);
|
||||
let bound_vars = self.tcx.late_bound_vars(fn_id);
|
||||
let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
|
||||
let ty = match self.tcx.asyncness(fn_id.owner) {
|
||||
|
@ -1339,7 +1349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
hir::Path { segments: [segment], .. },
|
||||
))
|
||||
| hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) => {
|
||||
let self_ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, ty);
|
||||
let self_ty = self.astconv().ast_ty_to_ty(ty);
|
||||
if let Ok(pick) = self.probe_for_name(
|
||||
Mode::Path,
|
||||
Ident::new(capitalized_name, segment.ident.span),
|
||||
|
|
|
@ -205,7 +205,7 @@ fn typeck_with_fallback<'tcx>(
|
|||
|
||||
if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
|
||||
let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
|
||||
<dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
|
||||
fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None)
|
||||
} else {
|
||||
tcx.fn_sig(def_id)
|
||||
};
|
||||
|
@ -220,7 +220,7 @@ fn typeck_with_fallback<'tcx>(
|
|||
} else {
|
||||
let expected_type = body_ty
|
||||
.and_then(|ty| match ty.kind {
|
||||
hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
|
||||
hir::TyKind::Infer => Some(fcx.astconv().ast_ty_to_ty(ty)),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or_else(|| match tcx.hir().get(id) {
|
||||
|
|
|
@ -4,6 +4,9 @@ use crate::{callee, FnCtxt};
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::GenericArg;
|
||||
use rustc_hir_analysis::astconv::generics::{
|
||||
check_generic_arg_count_for_call, create_substs_for_generic_args,
|
||||
};
|
||||
use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
|
||||
use rustc_infer::infer::{self, InferOk};
|
||||
use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
|
||||
|
@ -331,7 +334,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
// variables.
|
||||
let generics = self.tcx.generics_of(pick.item.def_id);
|
||||
|
||||
let arg_count_correct = <dyn AstConv<'_>>::check_generic_arg_count_for_call(
|
||||
let arg_count_correct = check_generic_arg_count_for_call(
|
||||
self.tcx,
|
||||
self.span,
|
||||
pick.item.def_id,
|
||||
|
@ -369,8 +372,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
) -> subst::GenericArg<'tcx> {
|
||||
match (¶m.kind, arg) {
|
||||
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
|
||||
<dyn AstConv<'_>>::ast_region_to_region(self.cfcx.fcx, lt, Some(param))
|
||||
.into()
|
||||
self.cfcx.fcx.astconv().ast_region_to_region(lt, Some(param)).into()
|
||||
}
|
||||
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
|
||||
self.cfcx.to_ty(ty).raw.into()
|
||||
|
@ -399,7 +401,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
let substs = <dyn AstConv<'_>>::create_substs_for_generic_args(
|
||||
let substs = create_substs_for_generic_args(
|
||||
self.tcx,
|
||||
pick.item.def_id,
|
||||
parent_substs,
|
||||
|
|
|
@ -9,6 +9,7 @@ use rustc_data_structures::fx::FxHashSet;
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir_analysis::autoderef::{self, Autoderef};
|
||||
use rustc_infer::infer::canonical::OriginalQueryValues;
|
||||
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
|
@ -29,7 +30,6 @@ use rustc_span::lev_distance::{
|
|||
};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP};
|
||||
use rustc_trait_selection::autoderef::{self, Autoderef};
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy;
|
||||
use rustc_trait_selection::traits::query::method_autoderef::{
|
||||
|
|
|
@ -3,6 +3,7 @@ use crate::{has_expected_num_generic_args, FnCtxt, PlaceOp};
|
|||
use rustc_ast as ast;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir_analysis::autoderef::Autoderef;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::InferOk;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast};
|
||||
|
@ -10,7 +11,6 @@ use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutabili
|
|||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::autoderef::Autoderef;
|
||||
use std::slice;
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
|
|
@ -55,6 +55,7 @@ use crate::infer::ExpectedFound;
|
|||
use crate::traits::error_reporting::report_object_safety_error;
|
||||
use crate::traits::{
|
||||
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
|
||||
PredicateObligation,
|
||||
};
|
||||
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
|
@ -91,8 +92,12 @@ pub mod nice_region_error;
|
|||
pub struct TypeErrCtxt<'a, 'tcx> {
|
||||
pub infcx: &'a InferCtxt<'tcx>,
|
||||
pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
|
||||
pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>,
|
||||
pub fallback_has_occurred: bool,
|
||||
|
||||
pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>,
|
||||
|
||||
pub autoderef_steps:
|
||||
Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, Vec<PredicateObligation<'tcx>>)> + 'a>,
|
||||
}
|
||||
|
||||
impl TypeErrCtxt<'_, '_> {
|
||||
|
|
|
@ -688,6 +688,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
typeck_results: None,
|
||||
fallback_has_occurred: false,
|
||||
normalize_fn_sig: Box::new(|fn_sig| fn_sig),
|
||||
autoderef_steps: Box::new(|ty| {
|
||||
debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck");
|
||||
vec![(ty, vec![])]
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/thir.html
|
||||
|
||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::RangeEnd;
|
||||
|
@ -575,6 +576,12 @@ impl<'tcx> Pat<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> IntoDiagnosticArg for Pat<'tcx> {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
format!("{}", self).into_diagnostic_arg()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, HashStable)]
|
||||
pub struct Ascription<'tcx> {
|
||||
pub annotation: CanonicalUserTypeAnnotation<'tcx>,
|
||||
|
|
|
@ -2,10 +2,10 @@ use crate::traits::{ObligationCause, ObligationCauseCode};
|
|||
use crate::ty::diagnostics::suggest_constraining_type_param;
|
||||
use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, Printer};
|
||||
use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
|
||||
use hir::def::DefKind;
|
||||
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
|
||||
use rustc_errors::{pluralize, Diagnostic, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::{BytePos, Span};
|
||||
|
@ -319,7 +319,11 @@ impl<'tcx> Ty<'tcx> {
|
|||
.into()
|
||||
}
|
||||
}
|
||||
ty::FnDef(..) => "fn item".into(),
|
||||
ty::FnDef(def_id, ..) => match tcx.def_kind(def_id) {
|
||||
DefKind::Ctor(CtorOf::Struct, _) => "struct constructor".into(),
|
||||
DefKind::Ctor(CtorOf::Variant, _) => "enum constructor".into(),
|
||||
_ => "fn item".into(),
|
||||
},
|
||||
ty::FnPtr(_) => "fn pointer".into(),
|
||||
ty::Dynamic(ref inner, ..) if let Some(principal) = inner.principal() => {
|
||||
format!("trait object `dyn {}`", tcx.def_path_str(principal.def_id())).into()
|
||||
|
@ -366,7 +370,11 @@ impl<'tcx> Ty<'tcx> {
|
|||
_ => "reference",
|
||||
}
|
||||
.into(),
|
||||
ty::FnDef(..) => "fn item".into(),
|
||||
ty::FnDef(def_id, ..) => match tcx.def_kind(def_id) {
|
||||
DefKind::Ctor(CtorOf::Struct, _) => "struct constructor".into(),
|
||||
DefKind::Ctor(CtorOf::Variant, _) => "enum constructor".into(),
|
||||
_ => "fn item".into(),
|
||||
},
|
||||
ty::FnPtr(_) => "fn pointer".into(),
|
||||
ty::Dynamic(..) => "trait object".into(),
|
||||
ty::Closure(..) => "closure".into(),
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
use crate::thir::pattern::deconstruct_pat::DeconstructedPat;
|
||||
use crate::thir::pattern::MatchCheckCtxt;
|
||||
use rustc_errors::Handler;
|
||||
use rustc_errors::{
|
||||
error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan,
|
||||
error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
||||
IntoDiagnostic, MultiSpan, SubdiagnosticMessage,
|
||||
};
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::thir::Pat;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::{symbol::Ident, Span};
|
||||
|
||||
|
@ -624,3 +628,223 @@ pub enum MultipleMutBorrowOccurence {
|
|||
name_moved: Ident,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_union_pattern)]
|
||||
pub struct UnionPattern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_type_not_structural)]
|
||||
pub struct TypeNotStructural<'tcx> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub non_sm_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_invalid_pattern)]
|
||||
pub struct InvalidPattern<'tcx> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub non_sm_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_unsized_pattern)]
|
||||
pub struct UnsizedPattern<'tcx> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub non_sm_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_float_pattern)]
|
||||
pub struct FloatPattern;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_pointer_pattern)]
|
||||
pub struct PointerPattern;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_indirect_structural_match)]
|
||||
pub struct IndirectStructuralMatch<'tcx> {
|
||||
pub non_sm_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_nontrivial_structural_match)]
|
||||
pub struct NontrivialStructuralMatch<'tcx> {
|
||||
pub non_sm_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_overlapping_range_endpoints)]
|
||||
#[note]
|
||||
pub struct OverlappingRangeEndpoints<'tcx> {
|
||||
#[label(range)]
|
||||
pub range: Span,
|
||||
#[subdiagnostic]
|
||||
pub overlap: Vec<Overlap<'tcx>>,
|
||||
}
|
||||
|
||||
pub struct Overlap<'tcx> {
|
||||
pub span: Span,
|
||||
pub range: Pat<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> AddToDiagnostic for Overlap<'tcx> {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
let Overlap { span, range } = self;
|
||||
|
||||
// FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]`
|
||||
// does not support `#[subdiagnostic(eager)]`...
|
||||
let message = format!("this range overlaps on `{range}`...");
|
||||
diag.span_label(span, message);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_non_exhaustive_omitted_pattern)]
|
||||
#[help]
|
||||
#[note]
|
||||
pub(crate) struct NonExhaustiveOmittedPattern<'tcx> {
|
||||
pub scrut_ty: Ty<'tcx>,
|
||||
#[subdiagnostic]
|
||||
pub uncovered: Uncovered<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(mir_build_uncovered)]
|
||||
pub(crate) struct Uncovered<'tcx> {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
count: usize,
|
||||
witness_1: Pat<'tcx>,
|
||||
witness_2: Pat<'tcx>,
|
||||
witness_3: Pat<'tcx>,
|
||||
remainder: usize,
|
||||
}
|
||||
|
||||
impl<'tcx> Uncovered<'tcx> {
|
||||
pub fn new<'p>(
|
||||
span: Span,
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
|
||||
) -> Self {
|
||||
let witness_1 = witnesses.get(0).unwrap().to_pat(cx);
|
||||
Self {
|
||||
span,
|
||||
count: witnesses.len(),
|
||||
// Substitute dummy values if witnesses is smaller than 3. These will never be read.
|
||||
witness_2: witnesses.get(1).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()),
|
||||
witness_3: witnesses.get(2).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()),
|
||||
witness_1,
|
||||
remainder: witnesses.len().saturating_sub(3),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_pattern_not_covered, code = "E0005")]
|
||||
pub(crate) struct PatternNotCovered<'s, 'tcx> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub origin: &'s str,
|
||||
#[subdiagnostic]
|
||||
pub uncovered: Uncovered<'tcx>,
|
||||
#[subdiagnostic]
|
||||
pub inform: Option<Inform>,
|
||||
#[subdiagnostic]
|
||||
pub interpreted_as_const: Option<InterpretedAsConst>,
|
||||
#[subdiagnostic]
|
||||
pub adt_defined_here: Option<AdtDefinedHere<'tcx>>,
|
||||
#[note(pattern_ty)]
|
||||
pub _p: (),
|
||||
pub pattern_ty: Ty<'tcx>,
|
||||
#[subdiagnostic]
|
||||
pub let_suggestion: Option<SuggestLet>,
|
||||
#[subdiagnostic]
|
||||
pub res_defined_here: Option<ResDefinedHere>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(mir_build_inform_irrefutable)]
|
||||
#[note(mir_build_more_information)]
|
||||
pub struct Inform;
|
||||
|
||||
pub struct AdtDefinedHere<'tcx> {
|
||||
pub adt_def_span: Span,
|
||||
pub ty: Ty<'tcx>,
|
||||
pub variants: Vec<Variant>,
|
||||
}
|
||||
|
||||
pub struct Variant {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<'tcx> AddToDiagnostic for AdtDefinedHere<'tcx> {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
diag.set_arg("ty", self.ty);
|
||||
let mut spans = MultiSpan::from(self.adt_def_span);
|
||||
|
||||
for Variant { span } in self.variants {
|
||||
spans.push_span_label(span, rustc_errors::fluent::mir_build_variant_defined_here);
|
||||
}
|
||||
|
||||
diag.span_note(spans, rustc_errors::fluent::mir_build_adt_defined_here);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(mir_build_res_defined_here)]
|
||||
pub struct ResDefinedHere {
|
||||
#[primary_span]
|
||||
pub def_span: Span,
|
||||
pub res: Res,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
mir_build_interpreted_as_const,
|
||||
code = "{variable}_var",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
#[label(mir_build_confused)]
|
||||
pub struct InterpretedAsConst {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub article: &'static str,
|
||||
pub variable: String,
|
||||
pub res: Res,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum SuggestLet {
|
||||
#[multipart_suggestion(mir_build_suggest_if_let, applicability = "has-placeholders")]
|
||||
If {
|
||||
#[suggestion_part(code = "if ")]
|
||||
start_span: Span,
|
||||
#[suggestion_part(code = " {{ todo!() }}")]
|
||||
semi_span: Span,
|
||||
count: usize,
|
||||
},
|
||||
#[suggestion(
|
||||
mir_build_suggest_let_else,
|
||||
code = " else {{ todo!() }}",
|
||||
applicability = "has-placeholders"
|
||||
)]
|
||||
Else {
|
||||
#[primary_span]
|
||||
end_span: Span,
|
||||
count: usize,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#![feature(let_chains)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(once_cell)]
|
||||
#![feature(try_blocks)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
@ -9,8 +9,7 @@ use crate::errors::*;
|
|||
use rustc_arena::TypedArena;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_errors::{
|
||||
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
||||
MultiSpan,
|
||||
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::*;
|
||||
|
@ -378,8 +377,8 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
|
|||
|
||||
let pattern = self.lower_pattern(&mut cx, pat, &mut false);
|
||||
let pattern_ty = pattern.ty();
|
||||
let arms = vec![MatchArm { pat: pattern, hir_id: pat.hir_id, has_guard: false }];
|
||||
let report = compute_match_usefulness(&cx, &arms, pat.hir_id, pattern_ty);
|
||||
let arm = MatchArm { pat: pattern, hir_id: pat.hir_id, has_guard: false };
|
||||
let report = compute_match_usefulness(&cx, &[arm], pat.hir_id, pattern_ty);
|
||||
|
||||
// Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We
|
||||
// only care about exhaustiveness here.
|
||||
|
@ -390,145 +389,73 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
let joined_patterns = joined_uncovered_patterns(&cx, &witnesses);
|
||||
|
||||
let mut bindings = vec![];
|
||||
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
pat.span,
|
||||
E0005,
|
||||
"refutable pattern in {}: {} not covered",
|
||||
origin,
|
||||
joined_patterns
|
||||
);
|
||||
let suggest_if_let = match &pat.kind {
|
||||
hir::PatKind::Path(hir::QPath::Resolved(None, path))
|
||||
if path.segments.len() == 1 && path.segments[0].args.is_none() =>
|
||||
let (inform, interpreted_as_const, res_defined_here,let_suggestion) =
|
||||
if let hir::PatKind::Path(hir::QPath::Resolved(
|
||||
None,
|
||||
hir::Path {
|
||||
segments: &[hir::PathSegment { args: None, res, ident, .. }],
|
||||
..
|
||||
},
|
||||
)) = &pat.kind
|
||||
{
|
||||
const_not_var(&mut err, cx.tcx, pat, path);
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
pat.walk(&mut |pat: &hir::Pat<'_>| {
|
||||
match pat.kind {
|
||||
hir::PatKind::Binding(_, _, ident, _) => {
|
||||
bindings.push(ident);
|
||||
(
|
||||
None,
|
||||
Some(InterpretedAsConst {
|
||||
span: pat.span,
|
||||
article: res.article(),
|
||||
variable: ident.to_string().to_lowercase(),
|
||||
res,
|
||||
}),
|
||||
try {
|
||||
ResDefinedHere {
|
||||
def_span: cx.tcx.hir().res_span(res)?,
|
||||
res,
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
None,
|
||||
)
|
||||
} else if let Some(span) = sp && self.tcx.sess.source_map().is_span_accessible(span) {
|
||||
let mut bindings = vec![];
|
||||
pat.walk_always(&mut |pat: &hir::Pat<'_>| {
|
||||
if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
|
||||
bindings.push(ident);
|
||||
}
|
||||
true
|
||||
});
|
||||
|
||||
err.span_label(pat.span, pattern_not_covered_label(&witnesses, &joined_patterns));
|
||||
true
|
||||
}
|
||||
};
|
||||
|
||||
if let (Some(span), true) = (sp, suggest_if_let) {
|
||||
err.note(
|
||||
"`let` bindings require an \"irrefutable pattern\", like a `struct` or \
|
||||
an `enum` with only one variant",
|
||||
);
|
||||
if self.tcx.sess.source_map().is_span_accessible(span) {
|
||||
let semi_span = span.shrink_to_hi().with_lo(span.hi() - BytePos(1));
|
||||
let start_span = span.shrink_to_lo();
|
||||
let end_span = semi_span.shrink_to_lo();
|
||||
err.multipart_suggestion(
|
||||
&format!(
|
||||
"you might want to use `if let` to ignore the variant{} that {} matched",
|
||||
pluralize!(witnesses.len()),
|
||||
match witnesses.len() {
|
||||
1 => "isn't",
|
||||
_ => "aren't",
|
||||
},
|
||||
),
|
||||
vec![
|
||||
match &bindings[..] {
|
||||
[] => (start_span, "if ".to_string()),
|
||||
[binding] => (start_span, format!("let {} = if ", binding)),
|
||||
bindings => (
|
||||
start_span,
|
||||
format!(
|
||||
"let ({}) = if ",
|
||||
bindings
|
||||
.iter()
|
||||
.map(|ident| ident.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
),
|
||||
},
|
||||
match &bindings[..] {
|
||||
[] => (semi_span, " { todo!() }".to_string()),
|
||||
[binding] => {
|
||||
(end_span, format!(" {{ {} }} else {{ todo!() }}", binding))
|
||||
}
|
||||
bindings => (
|
||||
end_span,
|
||||
format!(
|
||||
" {{ ({}) }} else {{ todo!() }}",
|
||||
bindings
|
||||
.iter()
|
||||
.map(|ident| ident.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
),
|
||||
},
|
||||
],
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
if !bindings.is_empty() {
|
||||
err.span_suggestion_verbose(
|
||||
semi_span.shrink_to_lo(),
|
||||
&format!(
|
||||
"alternatively, you might want to use \
|
||||
let else to handle the variant{} that {} matched",
|
||||
pluralize!(witnesses.len()),
|
||||
match witnesses.len() {
|
||||
1 => "isn't",
|
||||
_ => "aren't",
|
||||
},
|
||||
),
|
||||
" else { todo!() }",
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
let count = witnesses.len();
|
||||
|
||||
let let_suggestion = if bindings.is_empty() {SuggestLet::If{start_span, semi_span, count}} else{ SuggestLet::Else{end_span, count }};
|
||||
(sp.map(|_|Inform), None, None, Some(let_suggestion))
|
||||
} else{
|
||||
(sp.map(|_|Inform), None, None, None)
|
||||
};
|
||||
|
||||
let adt_defined_here = try {
|
||||
let ty = pattern_ty.peel_refs();
|
||||
let ty::Adt(def, _) = ty.kind() else { None? };
|
||||
let adt_def_span = cx.tcx.hir().get_if_local(def.did())?.ident()?.span;
|
||||
let mut variants = vec![];
|
||||
|
||||
for span in maybe_point_at_variant(&cx, *def, witnesses.iter().take(5)) {
|
||||
variants.push(Variant { span });
|
||||
}
|
||||
err.note(
|
||||
"for more information, visit \
|
||||
https://doc.rust-lang.org/book/ch18-02-refutability.html",
|
||||
);
|
||||
}
|
||||
AdtDefinedHere { adt_def_span, ty, variants }
|
||||
};
|
||||
|
||||
adt_defined_here(&cx, &mut err, pattern_ty, &witnesses);
|
||||
err.note(&format!("the matched value is of type `{}`", pattern_ty));
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
/// A path pattern was interpreted as a constant, not a new variable.
|
||||
/// This caused an irrefutable match failure in e.g. `let`.
|
||||
fn const_not_var(err: &mut Diagnostic, tcx: TyCtxt<'_>, pat: &Pat<'_>, path: &hir::Path<'_>) {
|
||||
let descr = path.res.descr();
|
||||
err.span_label(
|
||||
pat.span,
|
||||
format!("interpreted as {} {} pattern, not a new variable", path.res.article(), descr,),
|
||||
);
|
||||
|
||||
err.span_suggestion(
|
||||
pat.span,
|
||||
"introduce a variable instead",
|
||||
format!("{}_var", path.segments[0].ident).to_lowercase(),
|
||||
// Cannot use `MachineApplicable` as it's not really *always* correct
|
||||
// because there may be such an identifier in scope or the user maybe
|
||||
// really wanted to match against the constant. This is quite unlikely however.
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
||||
if let Some(span) = tcx.hir().res_span(path.res) {
|
||||
err.span_label(span, format!("{} defined here", descr));
|
||||
self.tcx.sess.emit_err(PatternNotCovered {
|
||||
span: pat.span,
|
||||
origin,
|
||||
uncovered: Uncovered::new(pat.span, &cx, witnesses),
|
||||
inform,
|
||||
interpreted_as_const,
|
||||
_p: (),
|
||||
pattern_ty,
|
||||
let_suggestion,
|
||||
res_defined_here,
|
||||
adt_defined_here,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
use rustc_errors::DelayDm;
|
||||
use rustc_hir as hir;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_middle::mir::{self, Field};
|
||||
use rustc_middle::thir::{FieldPat, Pat, PatKind};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::predicate_for_trait_def;
|
||||
|
@ -15,6 +13,10 @@ use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation};
|
|||
use std::cell::Cell;
|
||||
|
||||
use super::PatCtxt;
|
||||
use crate::errors::{
|
||||
FloatPattern, IndirectStructuralMatch, InvalidPattern, NontrivialStructuralMatch,
|
||||
PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
|
||||
};
|
||||
|
||||
impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
/// Converts an evaluated constant to a pattern (if possible).
|
||||
|
@ -105,47 +107,6 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn adt_derive_msg(&self, adt_def: AdtDef<'tcx>) -> String {
|
||||
let path = self.tcx().def_path_str(adt_def.did());
|
||||
format!(
|
||||
"to use a constant of type `{}` in a pattern, \
|
||||
`{}` must be annotated with `#[derive(PartialEq, Eq)]`",
|
||||
path, path,
|
||||
)
|
||||
}
|
||||
|
||||
fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String> {
|
||||
traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| {
|
||||
with_no_trimmed_paths!(match non_sm_ty.kind() {
|
||||
ty::Adt(adt, _) => self.adt_derive_msg(*adt),
|
||||
ty::Dynamic(..) => {
|
||||
"trait objects cannot be used in patterns".to_string()
|
||||
}
|
||||
ty::Alias(ty::Opaque, ..) => {
|
||||
"opaque types cannot be used in patterns".to_string()
|
||||
}
|
||||
ty::Closure(..) => {
|
||||
"closures cannot be used in patterns".to_string()
|
||||
}
|
||||
ty::Generator(..) | ty::GeneratorWitness(..) => {
|
||||
"generators cannot be used in patterns".to_string()
|
||||
}
|
||||
ty::Float(..) => {
|
||||
"floating-point numbers cannot be used in patterns".to_string()
|
||||
}
|
||||
ty::FnPtr(..) => {
|
||||
"function pointers cannot be used in patterns".to_string()
|
||||
}
|
||||
ty::RawPtr(..) => {
|
||||
"raw pointers cannot be used in patterns".to_string()
|
||||
}
|
||||
_ => {
|
||||
bug!("use of a value of `{non_sm_ty}` inside a pattern")
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
|
||||
ty.is_structural_eq_shallow(self.infcx.tcx)
|
||||
}
|
||||
|
@ -176,7 +137,8 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
// If we were able to successfully convert the const to some pat,
|
||||
// double-check that all types in the const implement `Structural`.
|
||||
|
||||
let structural = self.search_for_structural_match_violation(cv.ty());
|
||||
let structural =
|
||||
traits::search_for_structural_match_violation(self.span, self.tcx(), cv.ty());
|
||||
debug!(
|
||||
"search_for_structural_match_violation cv.ty: {:?} returned: {:?}",
|
||||
cv.ty(),
|
||||
|
@ -194,17 +156,18 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
return inlined_const_as_pat;
|
||||
}
|
||||
|
||||
if let Some(msg) = structural {
|
||||
if let Some(non_sm_ty) = structural {
|
||||
if !self.type_may_have_partial_eq_impl(cv.ty()) {
|
||||
// span_fatal avoids ICE from resolution of non-existent method (rare case).
|
||||
self.tcx().sess.span_fatal(self.span, &msg);
|
||||
// fatal avoids ICE from resolution of non-existent method (rare case).
|
||||
self.tcx()
|
||||
.sess
|
||||
.emit_fatal(TypeNotStructural { span: self.span, non_sm_ty: non_sm_ty });
|
||||
} else if mir_structural_match_violation && !self.saw_const_match_lint.get() {
|
||||
self.tcx().struct_span_lint_hir(
|
||||
self.tcx().emit_spanned_lint(
|
||||
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
|
||||
self.id,
|
||||
self.span,
|
||||
msg,
|
||||
|lint| lint,
|
||||
IndirectStructuralMatch { non_sm_ty },
|
||||
);
|
||||
} else {
|
||||
debug!(
|
||||
|
@ -278,12 +241,11 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
let kind = match cv.ty().kind() {
|
||||
ty::Float(_) => {
|
||||
if self.include_lint_checks {
|
||||
tcx.struct_span_lint_hir(
|
||||
tcx.emit_spanned_lint(
|
||||
lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
|
||||
id,
|
||||
span,
|
||||
"floating-point types cannot be used in patterns",
|
||||
|lint| lint,
|
||||
FloatPattern,
|
||||
);
|
||||
}
|
||||
PatKind::Constant { value: cv }
|
||||
|
@ -291,29 +253,22 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
ty::Adt(adt_def, _) if adt_def.is_union() => {
|
||||
// Matching on union fields is unsafe, we can't hide it in constants
|
||||
self.saw_const_match_error.set(true);
|
||||
let msg = "cannot use unions in constant patterns";
|
||||
if self.include_lint_checks {
|
||||
tcx.sess.span_err(span, msg);
|
||||
} else {
|
||||
tcx.sess.delay_span_bug(span, msg);
|
||||
}
|
||||
let err = UnionPattern { span };
|
||||
tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
|
||||
PatKind::Wild
|
||||
}
|
||||
ty::Adt(..)
|
||||
if !self.type_may_have_partial_eq_impl(cv.ty())
|
||||
// FIXME(#73448): Find a way to bring const qualification into parity with
|
||||
// `search_for_structural_match_violation` and then remove this condition.
|
||||
&& self.search_for_structural_match_violation(cv.ty()).is_some() =>
|
||||
|
||||
// Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
|
||||
// could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
|
||||
&& let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, cv.ty()) =>
|
||||
{
|
||||
// Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
|
||||
// could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
|
||||
let msg = self.search_for_structural_match_violation(cv.ty()).unwrap();
|
||||
self.saw_const_match_error.set(true);
|
||||
if self.include_lint_checks {
|
||||
tcx.sess.span_err(self.span, &msg);
|
||||
} else {
|
||||
tcx.sess.delay_span_bug(self.span, &msg);
|
||||
}
|
||||
let err = TypeNotStructural { span, non_sm_ty };
|
||||
tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
|
||||
PatKind::Wild
|
||||
}
|
||||
// If the type is not structurally comparable, just emit the constant directly,
|
||||
|
@ -331,19 +286,11 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
&& !self.saw_const_match_lint.get()
|
||||
{
|
||||
self.saw_const_match_lint.set(true);
|
||||
tcx.struct_span_lint_hir(
|
||||
tcx.emit_spanned_lint(
|
||||
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
|
||||
id,
|
||||
span,
|
||||
DelayDm(|| {
|
||||
format!(
|
||||
"to use a constant of type `{}` in a pattern, \
|
||||
`{}` must be annotated with `#[derive(PartialEq, Eq)]`",
|
||||
cv.ty(),
|
||||
cv.ty(),
|
||||
)
|
||||
}),
|
||||
|lint| lint,
|
||||
IndirectStructuralMatch { non_sm_ty: cv.ty() },
|
||||
);
|
||||
}
|
||||
// Since we are behind a reference, we can just bubble the error up so we get a
|
||||
|
@ -357,18 +304,9 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
adt_def,
|
||||
cv.ty()
|
||||
);
|
||||
let path = tcx.def_path_str(adt_def.did());
|
||||
let msg = format!(
|
||||
"to use a constant of type `{}` in a pattern, \
|
||||
`{}` must be annotated with `#[derive(PartialEq, Eq)]`",
|
||||
path, path,
|
||||
);
|
||||
self.saw_const_match_error.set(true);
|
||||
if self.include_lint_checks {
|
||||
tcx.sess.span_err(span, &msg);
|
||||
} else {
|
||||
tcx.sess.delay_span_bug(span, &msg);
|
||||
}
|
||||
let err = TypeNotStructural { span, non_sm_ty: cv.ty() };
|
||||
tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
|
||||
PatKind::Wild
|
||||
}
|
||||
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
|
||||
|
@ -401,12 +339,8 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
// These are not allowed and will error elsewhere anyway.
|
||||
ty::Dynamic(..) => {
|
||||
self.saw_const_match_error.set(true);
|
||||
let msg = format!("`{}` cannot be used in patterns", cv.ty());
|
||||
if self.include_lint_checks {
|
||||
tcx.sess.span_err(span, &msg);
|
||||
} else {
|
||||
tcx.sess.delay_span_bug(span, &msg);
|
||||
}
|
||||
let err = InvalidPattern { span, non_sm_ty: cv.ty() };
|
||||
tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
|
||||
PatKind::Wild
|
||||
}
|
||||
// `&str` is represented as `ConstValue::Slice`, let's keep using this
|
||||
|
@ -471,32 +405,26 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
// this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a
|
||||
// reference. This makes the rest of the matching logic simpler as it doesn't have
|
||||
// to figure out how to get a reference again.
|
||||
ty::Adt(adt_def, _) if !self.type_marked_structural(*pointee_ty) => {
|
||||
ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => {
|
||||
if self.behind_reference.get() {
|
||||
if self.include_lint_checks
|
||||
&& !self.saw_const_match_error.get()
|
||||
&& !self.saw_const_match_lint.get()
|
||||
{
|
||||
self.saw_const_match_lint.set(true);
|
||||
let msg = self.adt_derive_msg(adt_def);
|
||||
self.tcx().struct_span_lint_hir(
|
||||
self.saw_const_match_lint.set(true);
|
||||
tcx.emit_spanned_lint(
|
||||
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
|
||||
self.id,
|
||||
self.span,
|
||||
msg,
|
||||
|lint| lint,
|
||||
span,
|
||||
IndirectStructuralMatch { non_sm_ty: *pointee_ty },
|
||||
);
|
||||
}
|
||||
PatKind::Constant { value: cv }
|
||||
} else {
|
||||
if !self.saw_const_match_error.get() {
|
||||
self.saw_const_match_error.set(true);
|
||||
let msg = self.adt_derive_msg(adt_def);
|
||||
if self.include_lint_checks {
|
||||
tcx.sess.span_err(span, &msg);
|
||||
} else {
|
||||
tcx.sess.delay_span_bug(span, &msg);
|
||||
}
|
||||
let err = TypeNotStructural { span, non_sm_ty: *pointee_ty };
|
||||
tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
|
||||
}
|
||||
PatKind::Wild
|
||||
}
|
||||
|
@ -508,12 +436,10 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
if !pointee_ty.is_sized(tcx, param_env) {
|
||||
// `tcx.deref_mir_constant()` below will ICE with an unsized type
|
||||
// (except slices, which are handled in a separate arm above).
|
||||
let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty);
|
||||
if self.include_lint_checks {
|
||||
tcx.sess.span_err(span, &msg);
|
||||
} else {
|
||||
tcx.sess.delay_span_bug(span, &msg);
|
||||
}
|
||||
|
||||
let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
|
||||
tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
|
||||
|
||||
PatKind::Wild
|
||||
} else {
|
||||
let old = self.behind_reference.replace(true);
|
||||
|
@ -545,27 +471,19 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
&& !self.saw_const_match_lint.get()
|
||||
{
|
||||
self.saw_const_match_lint.set(true);
|
||||
let msg = "function pointers and unsized pointers in patterns behave \
|
||||
unpredictably and should not be relied upon. \
|
||||
See https://github.com/rust-lang/rust/issues/70861 for details.";
|
||||
tcx.struct_span_lint_hir(
|
||||
tcx.emit_spanned_lint(
|
||||
lint::builtin::POINTER_STRUCTURAL_MATCH,
|
||||
id,
|
||||
span,
|
||||
msg,
|
||||
|lint| lint,
|
||||
PointerPattern
|
||||
);
|
||||
}
|
||||
PatKind::Constant { value: cv }
|
||||
}
|
||||
_ => {
|
||||
self.saw_const_match_error.set(true);
|
||||
let msg = format!("`{}` cannot be used in patterns", cv.ty());
|
||||
if self.include_lint_checks {
|
||||
tcx.sess.span_err(span, &msg);
|
||||
} else {
|
||||
tcx.sess.delay_span_bug(span, &msg);
|
||||
}
|
||||
let err = InvalidPattern { span, non_sm_ty: cv.ty() };
|
||||
tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
|
||||
PatKind::Wild
|
||||
}
|
||||
};
|
||||
|
@ -576,21 +494,17 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
&& mir_structural_match_violation
|
||||
// FIXME(#73448): Find a way to bring const qualification into parity with
|
||||
// `search_for_structural_match_violation` and then remove this condition.
|
||||
&& self.search_for_structural_match_violation(cv.ty()).is_some()
|
||||
{
|
||||
self.saw_const_match_lint.set(true);
|
||||
|
||||
// Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
|
||||
// could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
|
||||
let msg = self.search_for_structural_match_violation(cv.ty()).unwrap().replace(
|
||||
"in a pattern,",
|
||||
"in a pattern, the constant's initializer must be trivial or",
|
||||
);
|
||||
tcx.struct_span_lint_hir(
|
||||
&& let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, cv.ty())
|
||||
{
|
||||
self.saw_const_match_lint.set(true);
|
||||
tcx.emit_spanned_lint(
|
||||
lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH,
|
||||
id,
|
||||
span,
|
||||
msg,
|
||||
|lint| lint,
|
||||
NontrivialStructuralMatch {non_sm_ty}
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ use self::SliceKind::*;
|
|||
|
||||
use super::compare_const_vals;
|
||||
use super::usefulness::{MatchCheckCtxt, PatCtxt};
|
||||
use crate::errors::{Overlap, OverlappingRangeEndpoints};
|
||||
|
||||
/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
|
||||
fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
|
||||
|
@ -96,7 +97,7 @@ fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
|
|||
/// `IntRange` is never used to encode an empty range or a "range" that wraps
|
||||
/// around the (offset) space: i.e., `range.lo <= range.hi`.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub(super) struct IntRange {
|
||||
pub(crate) struct IntRange {
|
||||
range: RangeInclusive<u128>,
|
||||
/// Keeps the bias used for encoding the range. It depends on the type of the range and
|
||||
/// possibly the pointer size of the current architecture. The algorithm ensures we never
|
||||
|
@ -284,32 +285,21 @@ impl IntRange {
|
|||
return;
|
||||
}
|
||||
|
||||
let overlaps: Vec<_> = pats
|
||||
let overlap: Vec<_> = pats
|
||||
.filter_map(|pat| Some((pat.ctor().as_int_range()?, pat.span())))
|
||||
.filter(|(range, _)| self.suspicious_intersection(range))
|
||||
.map(|(range, span)| (self.intersection(&range).unwrap(), span))
|
||||
.map(|(range, span)| Overlap {
|
||||
range: self.intersection(&range).unwrap().to_pat(pcx.cx.tcx, pcx.ty),
|
||||
span,
|
||||
})
|
||||
.collect();
|
||||
|
||||
if !overlaps.is_empty() {
|
||||
pcx.cx.tcx.struct_span_lint_hir(
|
||||
if !overlap.is_empty() {
|
||||
pcx.cx.tcx.emit_spanned_lint(
|
||||
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
|
||||
hir_id,
|
||||
pcx.span,
|
||||
"multiple patterns overlap on their endpoints",
|
||||
|lint| {
|
||||
for (int_range, span) in overlaps {
|
||||
lint.span_label(
|
||||
span,
|
||||
&format!(
|
||||
"this range overlaps on `{}`...",
|
||||
int_range.to_pat(pcx.cx.tcx, pcx.ty)
|
||||
),
|
||||
);
|
||||
}
|
||||
lint.span_label(pcx.span, "... with this range");
|
||||
lint.note("you likely meant to write mutually exclusive ranges");
|
||||
lint
|
||||
},
|
||||
OverlappingRangeEndpoints { overlap, range: pcx.span },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
mod check_match;
|
||||
mod const_to_pat;
|
||||
mod deconstruct_pat;
|
||||
pub(crate) mod deconstruct_pat;
|
||||
mod usefulness;
|
||||
|
||||
pub(crate) use self::check_match::check_match;
|
||||
|
|
|
@ -291,9 +291,8 @@
|
|||
|
||||
use self::ArmType::*;
|
||||
use self::Usefulness::*;
|
||||
|
||||
use super::check_match::{joined_uncovered_patterns, pattern_not_covered_label};
|
||||
use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard};
|
||||
use crate::errors::{NonExhaustiveOmittedPattern, Uncovered};
|
||||
|
||||
use rustc_data_structures::captures::Captures;
|
||||
|
||||
|
@ -743,31 +742,6 @@ impl<'p, 'tcx> Witness<'p, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
|
||||
/// is not exhaustive enough.
|
||||
///
|
||||
/// NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
|
||||
fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
scrut_ty: Ty<'tcx>,
|
||||
sp: Span,
|
||||
hir_id: HirId,
|
||||
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
|
||||
) {
|
||||
cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, "some variants are not matched explicitly", |lint| {
|
||||
let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
|
||||
lint.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
|
||||
lint.help(
|
||||
"ensure that all variants are matched explicitly by adding the suggested match arms",
|
||||
);
|
||||
lint.note(&format!(
|
||||
"the matched value is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
|
||||
scrut_ty,
|
||||
));
|
||||
lint
|
||||
});
|
||||
}
|
||||
|
||||
/// Algorithm from <http://moscova.inria.fr/~maranget/papers/warn/index.html>.
|
||||
/// The algorithm from the paper has been modified to correctly handle empty
|
||||
/// types. The changes are:
|
||||
|
@ -913,7 +887,19 @@ fn is_useful<'p, 'tcx>(
|
|||
.collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
lint_non_exhaustive_omitted_patterns(pcx.cx, pcx.ty, pcx.span, hir_id, patterns);
|
||||
// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
|
||||
// is not exhaustive enough.
|
||||
//
|
||||
// NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
|
||||
cx.tcx.emit_spanned_lint(
|
||||
NON_EXHAUSTIVE_OMITTED_PATTERNS,
|
||||
hir_id,
|
||||
pcx.span,
|
||||
NonExhaustiveOmittedPattern {
|
||||
scrut_ty: pcx.ty,
|
||||
uncovered: Uncovered::new(pcx.span, pcx.cx, patterns),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
ret.extend(usefulness);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use rustc_errors::{fluent, ErrorGuaranteed, Handler, IntoDiagnostic};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_middle::ty::{self, PolyTraitRef, Ty};
|
||||
use rustc_session::Limit;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
@ -21,18 +20,6 @@ pub struct UnableToConstructConstantValue<'a> {
|
|||
pub unevaluated: ty::UnevaluatedConst<'a>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[help]
|
||||
#[diag(trait_selection_auto_deref_reached_recursion_limit, code = "E0055")]
|
||||
pub struct AutoDerefReachedRecursionLimit<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub ty: Ty<'a>,
|
||||
pub suggested_limit: Limit,
|
||||
pub crate_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(trait_selection_empty_on_clause_in_rustc_on_unimplemented, code = "E0232")]
|
||||
pub struct EmptyOnClauseInOnUnimplemented {
|
||||
|
|
|
@ -35,7 +35,6 @@ extern crate rustc_middle;
|
|||
#[macro_use]
|
||||
extern crate smallvec;
|
||||
|
||||
pub mod autoderef;
|
||||
pub mod errors;
|
||||
pub mod infer;
|
||||
pub mod solve;
|
||||
|
|
|
@ -5,7 +5,6 @@ use super::{
|
|||
PredicateObligation,
|
||||
};
|
||||
|
||||
use crate::autoderef::Autoderef;
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::traits::{NormalizeExt, ObligationCtxt};
|
||||
|
||||
|
@ -750,26 +749,30 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
|
||||
if let ty::Ref(region, base_ty, mutbl) = *real_ty.skip_binder().kind() {
|
||||
let mut autoderef = Autoderef::new(
|
||||
self,
|
||||
obligation.param_env,
|
||||
obligation.cause.body_id,
|
||||
span,
|
||||
base_ty,
|
||||
);
|
||||
if let Some(steps) = autoderef.find_map(|(ty, steps)| {
|
||||
// Re-add the `&`
|
||||
let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
|
||||
let autoderef = (self.autoderef_steps)(base_ty);
|
||||
if let Some(steps) =
|
||||
autoderef.into_iter().enumerate().find_map(|(steps, (ty, obligations))| {
|
||||
// Re-add the `&`
|
||||
let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
|
||||
|
||||
// Remapping bound vars here
|
||||
let real_trait_pred_and_ty =
|
||||
real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));
|
||||
let obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||
obligation.param_env,
|
||||
real_trait_pred_and_ty,
|
||||
);
|
||||
Some(steps).filter(|_| self.predicate_may_hold(&obligation))
|
||||
}) {
|
||||
// Remapping bound vars here
|
||||
let real_trait_pred_and_ty =
|
||||
real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));
|
||||
let obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||
obligation.param_env,
|
||||
real_trait_pred_and_ty,
|
||||
);
|
||||
if obligations
|
||||
.iter()
|
||||
.chain([&obligation])
|
||||
.all(|obligation| self.predicate_may_hold(obligation))
|
||||
{
|
||||
Some(steps)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
{
|
||||
if steps > 0 {
|
||||
// Don't care about `&mut` because `DerefMut` is used less
|
||||
// often and user will not expect autoderef happens.
|
||||
|
@ -1358,57 +1361,117 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
err: &mut Diagnostic,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool {
|
||||
let span = obligation.cause.span;
|
||||
let mut span = obligation.cause.span;
|
||||
let mut trait_pred = trait_pred;
|
||||
let mut code = obligation.cause.code();
|
||||
while let Some((c, Some(parent_trait_pred))) = code.parent() {
|
||||
// We want the root obligation, in order to detect properly handle
|
||||
// `for _ in &mut &mut vec![] {}`.
|
||||
code = c;
|
||||
trait_pred = parent_trait_pred;
|
||||
}
|
||||
while span.desugaring_kind().is_some() {
|
||||
// Remove all the hir desugaring contexts while maintaining the macro contexts.
|
||||
span.remove_mark();
|
||||
}
|
||||
let mut expr_finder = super::FindExprBySpan::new(span);
|
||||
let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else {
|
||||
return false;
|
||||
};
|
||||
expr_finder.visit_expr(&body);
|
||||
let mut maybe_suggest = |suggested_ty, count, suggestions| {
|
||||
// Remapping bound vars here
|
||||
let trait_pred_and_suggested_ty =
|
||||
trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
|
||||
|
||||
let mut suggested = false;
|
||||
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
|
||||
let refs_number =
|
||||
snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count();
|
||||
if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) {
|
||||
// Do not suggest removal of borrow from type arguments.
|
||||
return false;
|
||||
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||
obligation.param_env,
|
||||
trait_pred_and_suggested_ty,
|
||||
);
|
||||
|
||||
if self.predicate_may_hold(&new_obligation) {
|
||||
let msg = if count == 1 {
|
||||
"consider removing the leading `&`-reference".to_string()
|
||||
} else {
|
||||
format!("consider removing {count} leading `&`-references")
|
||||
};
|
||||
|
||||
err.multipart_suggestion_verbose(
|
||||
&msg,
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
// Skipping binder here, remapping below
|
||||
let mut suggested_ty = trait_pred.self_ty().skip_binder();
|
||||
// Maybe suggest removal of borrows from types in type parameters, like in
|
||||
// `src/test/ui/not-panic/not-panic-safe.rs`.
|
||||
let mut count = 0;
|
||||
let mut suggestions = vec![];
|
||||
// Skipping binder here, remapping below
|
||||
let mut suggested_ty = trait_pred.self_ty().skip_binder();
|
||||
if let Some(mut hir_ty) = expr_finder.ty_result {
|
||||
while let hir::TyKind::Ref(_, mut_ty) = &hir_ty.kind {
|
||||
count += 1;
|
||||
let span = hir_ty.span.until(mut_ty.ty.span);
|
||||
suggestions.push((span, String::new()));
|
||||
|
||||
for refs_remaining in 0..refs_number {
|
||||
let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
|
||||
break;
|
||||
};
|
||||
suggested_ty = *inner_ty;
|
||||
|
||||
// Remapping bound vars here
|
||||
let trait_pred_and_suggested_ty =
|
||||
trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
|
||||
hir_ty = mut_ty.ty;
|
||||
|
||||
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||
obligation.param_env,
|
||||
trait_pred_and_suggested_ty,
|
||||
);
|
||||
|
||||
if self.predicate_may_hold(&new_obligation) {
|
||||
let sp = self
|
||||
.tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_take_while(span, |c| c.is_whitespace() || *c == '&');
|
||||
|
||||
let remove_refs = refs_remaining + 1;
|
||||
|
||||
let msg = if remove_refs == 1 {
|
||||
"consider removing the leading `&`-reference".to_string()
|
||||
} else {
|
||||
format!("consider removing {} leading `&`-references", remove_refs)
|
||||
};
|
||||
|
||||
err.span_suggestion_short(sp, &msg, "", Applicability::MachineApplicable);
|
||||
suggested = true;
|
||||
break;
|
||||
if maybe_suggest(suggested_ty, count, suggestions.clone()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
suggested
|
||||
|
||||
// Maybe suggest removal of borrows from expressions, like in `for i in &&&foo {}`.
|
||||
let Some(mut expr) = expr_finder.result else { return false; };
|
||||
let mut count = 0;
|
||||
let mut suggestions = vec![];
|
||||
// Skipping binder here, remapping below
|
||||
let mut suggested_ty = trait_pred.self_ty().skip_binder();
|
||||
'outer: loop {
|
||||
while let hir::ExprKind::AddrOf(_, _, borrowed) = expr.kind {
|
||||
count += 1;
|
||||
let span = if expr.span.eq_ctxt(borrowed.span) {
|
||||
expr.span.until(borrowed.span)
|
||||
} else {
|
||||
expr.span.with_hi(expr.span.lo() + BytePos(1))
|
||||
};
|
||||
suggestions.push((span, String::new()));
|
||||
|
||||
let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
|
||||
break 'outer;
|
||||
};
|
||||
suggested_ty = *inner_ty;
|
||||
|
||||
expr = borrowed;
|
||||
|
||||
if maybe_suggest(suggested_ty, count, suggestions.clone()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
|
||||
&& let hir::def::Res::Local(hir_id) = path.res
|
||||
&& let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(hir_id)
|
||||
&& let Some(hir::Node::Local(local)) = self.tcx.hir().find_parent(binding.hir_id)
|
||||
&& let None = local.ty
|
||||
&& let Some(binding_expr) = local.init
|
||||
{
|
||||
expr = binding_expr;
|
||||
} else {
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue