Rollup merge of #148837 - estebank:let-else, r=Kivooeo
Use `let...else` instead of `match foo { ... _ => return };` and `if let ... else return`
This commit is contained in:
commit
b32845c61a
47 changed files with 285 additions and 392 deletions
|
|
@ -1533,11 +1533,10 @@ impl Expr {
|
|||
// then type of result is trait object.
|
||||
// Otherwise we don't assume the result type.
|
||||
ExprKind::Binary(binop, lhs, rhs) if binop.node == BinOpKind::Add => {
|
||||
if let (Some(lhs), Some(rhs)) = (lhs.to_bound(), rhs.to_bound()) {
|
||||
TyKind::TraitObject(vec![lhs, rhs], TraitObjectSyntax::None)
|
||||
} else {
|
||||
let (Some(lhs), Some(rhs)) = (lhs.to_bound(), rhs.to_bound()) else {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
TyKind::TraitObject(vec![lhs, rhs], TraitObjectSyntax::None)
|
||||
}
|
||||
|
||||
ExprKind::Underscore => TyKind::Infer,
|
||||
|
|
|
|||
|
|
@ -447,20 +447,17 @@ impl MetaItem {
|
|||
thin_vec![PathSegment::path_root(span)]
|
||||
};
|
||||
loop {
|
||||
if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
|
||||
let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
|
||||
iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref()
|
||||
{
|
||||
segments.push(PathSegment::from_ident(Ident::new(name, span)));
|
||||
} else {
|
||||
else {
|
||||
return None;
|
||||
}
|
||||
if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
|
||||
iter.peek()
|
||||
{
|
||||
iter.next();
|
||||
} else {
|
||||
};
|
||||
segments.push(PathSegment::from_ident(Ident::new(name, span)));
|
||||
let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = iter.peek()
|
||||
else {
|
||||
break;
|
||||
}
|
||||
};
|
||||
iter.next();
|
||||
}
|
||||
let span = span.with_hi(segments.last().unwrap().ident.span.hi());
|
||||
Path { span, segments, tokens: None }
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![deny(clippy::manual_let_else)]
|
||||
#![doc(test(attr(deny(warnings), allow(internal_features))))]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(box_patterns)]
|
||||
|
|
|
|||
|
|
@ -561,11 +561,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
VarDebugInfoContents::Place(ref p) => p == place,
|
||||
_ => false,
|
||||
});
|
||||
let arg_name = if let Some(var_info) = var_info {
|
||||
var_info.name
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
let Some(var_info) = var_info else { return };
|
||||
let arg_name = var_info.name;
|
||||
struct MatchArgFinder {
|
||||
expr_span: Span,
|
||||
match_arg_span: Option<Span>,
|
||||
|
|
|
|||
|
|
@ -850,16 +850,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
|||
// will only ever have one item at any given time, but by using a vector, we can pop from
|
||||
// it which simplifies the termination logic.
|
||||
let mut queue = vec![location];
|
||||
let mut target =
|
||||
if let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) = stmt {
|
||||
if let Some(local) = place.as_local() {
|
||||
local
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) = stmt else {
|
||||
return false;
|
||||
};
|
||||
let Some(mut target) = place.as_local() else { return false };
|
||||
|
||||
debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue);
|
||||
while let Some(current_location) = queue.pop() {
|
||||
|
|
|
|||
|
|
@ -1124,16 +1124,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
use self::UseSpans::*;
|
||||
debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
|
||||
|
||||
let target = match self.body[location.block].statements.get(location.statement_index) {
|
||||
Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) => {
|
||||
if let Some(local) = place.as_local() {
|
||||
local
|
||||
} else {
|
||||
return OtherUse(use_span);
|
||||
}
|
||||
}
|
||||
_ => return OtherUse(use_span),
|
||||
let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) =
|
||||
self.body[location.block].statements.get(location.statement_index)
|
||||
else {
|
||||
return OtherUse(use_span);
|
||||
};
|
||||
let Some(target) = place.as_local() else { return OtherUse(use_span) };
|
||||
|
||||
if self.body.local_kind(target) != LocalKind::Temp {
|
||||
// operands are always temporaries.
|
||||
|
|
|
|||
|
|
@ -142,12 +142,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
} else {
|
||||
item_msg = access_place_desc;
|
||||
let local_info = self.body.local_decls[local].local_info();
|
||||
if let LocalInfo::StaticRef { def_id, .. } = *local_info {
|
||||
let static_name = &self.infcx.tcx.item_name(def_id);
|
||||
reason = format!(", as `{static_name}` is an immutable static item");
|
||||
} else {
|
||||
let LocalInfo::StaticRef { def_id, .. } = *local_info else {
|
||||
bug!("is_ref_to_static return true, but not ref to static?");
|
||||
}
|
||||
};
|
||||
let static_name = &self.infcx.tcx.item_name(def_id);
|
||||
reason = format!(", as `{static_name}` is an immutable static item");
|
||||
}
|
||||
}
|
||||
PlaceRef { local, projection: [proj_base @ .., ProjectionElem::Deref] } => {
|
||||
|
|
|
|||
|
|
@ -847,11 +847,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
|
||||
let fn_returns = self.infcx.tcx.return_type_impl_or_dyn_traits(suitable_region.scope);
|
||||
|
||||
let param = if let Some(param) =
|
||||
let Some(param) =
|
||||
find_param_with_region(self.infcx.tcx, self.mir_def_id(), f, outlived_f)
|
||||
{
|
||||
param
|
||||
} else {
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -930,37 +928,27 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
let instance = if let ConstraintCategory::CallArgument(Some(func_ty)) = category {
|
||||
let (fn_did, args) = match func_ty.kind() {
|
||||
ty::FnDef(fn_did, args) => (fn_did, args),
|
||||
_ => return,
|
||||
};
|
||||
debug!(?fn_did, ?args);
|
||||
let ConstraintCategory::CallArgument(Some(func_ty)) = category else { return };
|
||||
let ty::FnDef(fn_did, args) = func_ty.kind() else { return };
|
||||
debug!(?fn_did, ?args);
|
||||
|
||||
// Only suggest this on function calls, not closures
|
||||
let ty = tcx.type_of(fn_did).instantiate_identity();
|
||||
debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind());
|
||||
if let ty::Closure(_, _) = ty.kind() {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Ok(Some(instance)) = ty::Instance::try_resolve(
|
||||
tcx,
|
||||
self.infcx.typing_env(self.infcx.param_env),
|
||||
*fn_did,
|
||||
self.infcx.resolve_vars_if_possible(args),
|
||||
) {
|
||||
instance
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Only suggest this on function calls, not closures
|
||||
let ty = tcx.type_of(fn_did).instantiate_identity();
|
||||
debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind());
|
||||
if let ty::Closure(_, _) = ty.kind() {
|
||||
return;
|
||||
}
|
||||
let Ok(Some(instance)) = ty::Instance::try_resolve(
|
||||
tcx,
|
||||
self.infcx.typing_env(self.infcx.param_env),
|
||||
*fn_did,
|
||||
self.infcx.resolve_vars_if_possible(args),
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let param = match find_param_with_region(tcx, self.mir_def_id(), f, o) {
|
||||
Some(param) => param,
|
||||
None => return,
|
||||
let Some(param) = find_param_with_region(tcx, self.mir_def_id(), f, o) else {
|
||||
return;
|
||||
};
|
||||
debug!(?param);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![deny(clippy::manual_let_else)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(file_buffered)]
|
||||
|
|
|
|||
|
|
@ -67,12 +67,11 @@ impl<'a, 'tcx> Visitor<'tcx> for AccessFactsExtractor<'a, 'tcx> {
|
|||
match context {
|
||||
PlaceContext::NonMutatingUse(_)
|
||||
| PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
|
||||
let path = match self.move_data.rev_lookup.find(place.as_ref()) {
|
||||
LookupResult::Exact(path) | LookupResult::Parent(Some(path)) => path,
|
||||
_ => {
|
||||
// There's no path access to emit.
|
||||
return;
|
||||
}
|
||||
let (LookupResult::Exact(path) | LookupResult::Parent(Some(path))) =
|
||||
self.move_data.rev_lookup.find(place.as_ref())
|
||||
else {
|
||||
// There's no path access to emit.
|
||||
return;
|
||||
};
|
||||
debug!("AccessFactsExtractor - emit path access ({path:?}, {location:?})");
|
||||
self.facts.path_accessed_at_base.push((path, self.location_to_index(location)));
|
||||
|
|
|
|||
|
|
@ -130,11 +130,9 @@ impl UnwindContext {
|
|||
return;
|
||||
}
|
||||
|
||||
let unwind_info = if let Some(unwind_info) =
|
||||
let Some(unwind_info) =
|
||||
context.compiled_code().unwrap().create_unwind_info(module.isa()).unwrap()
|
||||
{
|
||||
unwind_info
|
||||
} else {
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -29,11 +29,7 @@ pub(crate) fn maybe_known_branch_taken(
|
|||
arg: Value,
|
||||
test_zero: bool,
|
||||
) -> Option<bool> {
|
||||
let arg_inst = if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
|
||||
arg_inst
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) else { return None };
|
||||
|
||||
match bcx.func.dfg.insts[arg_inst] {
|
||||
InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => {
|
||||
|
|
|
|||
|
|
@ -774,24 +774,23 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
return Err(());
|
||||
}};
|
||||
}
|
||||
let (elem_ty_str, elem_ty, cast_type) = if let ty::Float(ref f) = *in_elem.kind() {
|
||||
let elem_ty = bx.cx.type_float_from_ty(*f);
|
||||
match f.bit_width() {
|
||||
16 => ("", elem_ty, Some(bx.cx.double_type)),
|
||||
32 => ("f", elem_ty, None),
|
||||
64 => ("", elem_ty, None),
|
||||
_ => {
|
||||
return_error!(InvalidMonomorphization::FloatingPointVector {
|
||||
span,
|
||||
name,
|
||||
f_ty: *f,
|
||||
in_ty
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let ty::Float(ref f) = *in_elem.kind() else {
|
||||
return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty });
|
||||
};
|
||||
let elem_ty = bx.cx.type_float_from_ty(*f);
|
||||
let (elem_ty_str, elem_ty, cast_type) = match f.bit_width() {
|
||||
16 => ("", elem_ty, Some(bx.cx.double_type)),
|
||||
32 => ("f", elem_ty, None),
|
||||
64 => ("", elem_ty, None),
|
||||
_ => {
|
||||
return_error!(InvalidMonomorphization::FloatingPointVector {
|
||||
span,
|
||||
name,
|
||||
f_ty: *f,
|
||||
in_ty
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let vec_ty = bx.cx.type_vector(elem_ty, in_len);
|
||||
|
||||
|
|
|
|||
|
|
@ -1756,11 +1756,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
}};
|
||||
}
|
||||
|
||||
let elem_ty = if let ty::Float(f) = in_elem.kind() {
|
||||
bx.cx.type_float_from_ty(*f)
|
||||
} else {
|
||||
let ty::Float(f) = in_elem.kind() else {
|
||||
return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty });
|
||||
};
|
||||
let elem_ty = bx.cx.type_float_from_ty(*f);
|
||||
|
||||
let vec_ty = bx.type_vector(elem_ty, in_len);
|
||||
|
||||
|
|
|
|||
|
|
@ -721,11 +721,10 @@ pub fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
|
|||
};
|
||||
|
||||
// First read the ret symbol from the attribute
|
||||
let ret_symbol = if let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = ret_activity {
|
||||
p1.segments.first().unwrap().ident
|
||||
} else {
|
||||
let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = ret_activity else {
|
||||
span_bug!(attr.span(), "rustc_autodiff attribute must contain the return activity");
|
||||
};
|
||||
let ret_symbol = p1.segments.first().unwrap().ident;
|
||||
|
||||
// Then parse it into an actual DiffActivity
|
||||
let Ok(ret_activity) = DiffActivity::from_str(ret_symbol.as_str()) else {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
// tidy-alphabetical-start
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![deny(clippy::manual_let_else)]
|
||||
#![feature(array_try_map)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
|
|
|
|||
|
|
@ -788,11 +788,10 @@ pub fn compile_declarative_macro(
|
|||
let lhs_span = lhs_tt.span();
|
||||
// Convert the lhs into `MatcherLoc` form, which is better for doing the
|
||||
// actual matching.
|
||||
let lhs = if let mbe::TokenTree::Delimited(.., delimited) = lhs_tt {
|
||||
mbe::macro_parser::compute_locs(&delimited.tts)
|
||||
} else {
|
||||
let mbe::TokenTree::Delimited(.., delimited) = lhs_tt else {
|
||||
return dummy_syn_ext(guar.unwrap());
|
||||
};
|
||||
let lhs = mbe::macro_parser::compute_locs(&delimited.tts);
|
||||
if let Some(args) = args {
|
||||
let args_span = args.span();
|
||||
let mbe::TokenTree::Delimited(.., delimited) = args else {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![cfg_attr(bootstrap, feature(debug_closure_helpers))]
|
||||
#![deny(clippy::manual_let_else)]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(closure_track_caller)]
|
||||
#![feature(const_default)]
|
||||
|
|
|
|||
|
|
@ -1551,15 +1551,15 @@ fn const_param_default<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
|
||||
let default_ct = match tcx.hir_node_by_def_id(def_id) {
|
||||
hir::Node::GenericParam(hir::GenericParam {
|
||||
kind: hir::GenericParamKind::Const { default: Some(ct), .. },
|
||||
..
|
||||
}) => ct,
|
||||
_ => span_bug!(
|
||||
let hir::Node::GenericParam(hir::GenericParam {
|
||||
kind: hir::GenericParamKind::Const { default: Some(default_ct), .. },
|
||||
..
|
||||
}) = tcx.hir_node_by_def_id(def_id)
|
||||
else {
|
||||
span_bug!(
|
||||
tcx.def_span(def_id),
|
||||
"`const_param_default` expected a generic parameter with a constant"
|
||||
),
|
||||
)
|
||||
};
|
||||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
|
||||
|
|
|
|||
|
|
@ -188,29 +188,26 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>(
|
|||
for (param, var) in std::iter::zip(&generics.own_params, gat_vars) {
|
||||
let existing = match var.kind() {
|
||||
ty::GenericArgKind::Lifetime(re) => {
|
||||
if let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) =
|
||||
let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) =
|
||||
re.kind()
|
||||
{
|
||||
mapping.insert(bv.var, tcx.mk_param_from_def(param))
|
||||
} else {
|
||||
else {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
mapping.insert(bv.var, tcx.mk_param_from_def(param))
|
||||
}
|
||||
ty::GenericArgKind::Type(ty) => {
|
||||
if let ty::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = *ty.kind() {
|
||||
mapping.insert(bv.var, tcx.mk_param_from_def(param))
|
||||
} else {
|
||||
let ty::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = *ty.kind() else {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
mapping.insert(bv.var, tcx.mk_param_from_def(param))
|
||||
}
|
||||
ty::GenericArgKind::Const(ct) => {
|
||||
if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) =
|
||||
let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) =
|
||||
ct.kind()
|
||||
{
|
||||
mapping.insert(bv.var, tcx.mk_param_from_def(param))
|
||||
} else {
|
||||
else {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
mapping.insert(bv.var, tcx.mk_param_from_def(param))
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -763,9 +763,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||
&self,
|
||||
err: &mut Diag<'_, impl EmissionGuarantee>,
|
||||
) {
|
||||
let trait_ = match self.tcx.trait_of_assoc(self.def_id) {
|
||||
Some(def_id) => def_id,
|
||||
None => return,
|
||||
let Some(trait_) = self.tcx.trait_of_assoc(self.def_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Skip suggestion when the associated function is itself generic, it is unclear
|
||||
|
|
@ -1077,15 +1076,11 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||
|
||||
/// Builds the `type defined here` message.
|
||||
fn show_definition(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
|
||||
let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) {
|
||||
if self.tcx.sess.source_map().is_span_accessible(def_span) {
|
||||
def_span.into()
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
let Some(def_span) = self.tcx.def_ident_span(self.def_id) else { return };
|
||||
if !self.tcx.sess.source_map().is_span_accessible(def_span) {
|
||||
return;
|
||||
};
|
||||
let mut spans: MultiSpan = def_span.into();
|
||||
|
||||
let msg = {
|
||||
let def_kind = self.tcx.def_descr(self.def_id);
|
||||
|
|
|
|||
|
|
@ -1749,10 +1749,8 @@ fn generics_args_err_extend<'a>(
|
|||
GenericsArgsErrExtend::SelfTyAlias { def_id, span } => {
|
||||
let ty = tcx.at(span).type_of(def_id).instantiate_identity();
|
||||
let span_of_impl = tcx.span_of_impl(def_id);
|
||||
let def_id = match *ty.kind() {
|
||||
ty::Adt(self_def, _) => self_def.did(),
|
||||
_ => return,
|
||||
};
|
||||
let ty::Adt(self_def, _) = *ty.kind() else { return };
|
||||
let def_id = self_def.did();
|
||||
|
||||
let type_name = tcx.item_name(def_id);
|
||||
let span_of_ty = tcx.def_ident_span(def_id);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ This API is completely unstable and subject to change.
|
|||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
#![cfg_attr(bootstrap, feature(debug_closure_helpers))]
|
||||
#![deny(clippy::manual_let_else)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(gen_blocks)]
|
||||
#![feature(if_let_guard)]
|
||||
|
|
|
|||
|
|
@ -458,15 +458,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
{
|
||||
// Actually need to unwrap one more layer of HIR to get to
|
||||
// the _real_ closure...
|
||||
if let hir::Node::Expr(&hir::Expr {
|
||||
let hir::Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
|
||||
..
|
||||
}) = self.tcx.parent_hir_node(parent_hir_id)
|
||||
{
|
||||
fn_decl_span
|
||||
} else {
|
||||
else {
|
||||
return;
|
||||
}
|
||||
};
|
||||
fn_decl_span
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -415,11 +415,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
});
|
||||
Some(self.resolve_vars_if_possible(possible_rcvr_ty))
|
||||
});
|
||||
if let Some(rcvr_ty) = possible_rcvr_ty {
|
||||
rcvr_ty
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
let Some(rcvr_ty) = possible_rcvr_ty else { return false };
|
||||
rcvr_ty
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1561,19 +1561,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
base_place: PlaceWithHirId<'tcx>,
|
||||
) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
|
||||
let base_curr_ty = base_place.place.ty();
|
||||
let deref_ty = match self
|
||||
let Some(deref_ty) = self
|
||||
.cx
|
||||
.structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty)
|
||||
.builtin_deref(true)
|
||||
{
|
||||
Some(ty) => ty,
|
||||
None => {
|
||||
debug!("explicit deref of non-derefable type: {:?}", base_curr_ty);
|
||||
return Err(self.cx.report_bug(
|
||||
self.cx.tcx().hir_span(node),
|
||||
"explicit deref of non-derefable type",
|
||||
));
|
||||
}
|
||||
else {
|
||||
debug!("explicit deref of non-derefable type: {:?}", base_curr_ty);
|
||||
return Err(self
|
||||
.cx
|
||||
.report_bug(self.cx.tcx().hir_span(node), "explicit deref of non-derefable type"));
|
||||
};
|
||||
let mut projections = base_place.place.projections;
|
||||
projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty });
|
||||
|
|
|
|||
|
|
@ -48,33 +48,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
let uninstantiated_pred = match flavor {
|
||||
ClauseFlavor::Where => {
|
||||
ClauseFlavor::Where
|
||||
if let Some(pred) = self
|
||||
.tcx
|
||||
.predicates_of(def_id)
|
||||
.instantiate_identity(self.tcx)
|
||||
.predicates
|
||||
.into_iter()
|
||||
.nth(idx)
|
||||
{
|
||||
pred
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
.nth(idx) =>
|
||||
{
|
||||
pred
|
||||
}
|
||||
ClauseFlavor::Const => {
|
||||
ClauseFlavor::Const
|
||||
if let Some((pred, _)) = self
|
||||
.tcx
|
||||
.const_conditions(def_id)
|
||||
.instantiate_identity(self.tcx)
|
||||
.into_iter()
|
||||
.nth(idx)
|
||||
{
|
||||
pred.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe)
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
.nth(idx) =>
|
||||
{
|
||||
pred.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe)
|
||||
}
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
|
|
|
|||
|
|
@ -1467,11 +1467,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
_ => None,
|
||||
}
|
||||
});
|
||||
if let Some(new_def_id) = new_def_id {
|
||||
def_id = new_def_id;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
let Some(new_def_id) = new_def_id else { return };
|
||||
def_id = new_def_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1795,7 +1795,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Some(ty),
|
||||
hir::Path { segments: [segment], .. },
|
||||
))
|
||||
| hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) => {
|
||||
| hir::ExprKind::Path(QPath::TypeRelative(ty, segment))
|
||||
if let Some(self_ty) = self.typeck_results.borrow().node_type_opt(ty.hir_id)
|
||||
&& let Ok(pick) = self.probe_for_name(
|
||||
Mode::Path,
|
||||
|
|
@ -1805,12 +1805,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self_ty,
|
||||
expr.hir_id,
|
||||
ProbeScope::TraitsInScope,
|
||||
)
|
||||
{
|
||||
(pick.item, segment)
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
) =>
|
||||
{
|
||||
(pick.item, segment)
|
||||
}
|
||||
hir::ExprKind::Path(QPath::Resolved(
|
||||
None,
|
||||
|
|
@ -1821,16 +1818,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if old_item_name != segment.ident.name {
|
||||
return false;
|
||||
}
|
||||
if let Some(item) = self
|
||||
let Some(item) = self
|
||||
.tcx
|
||||
.associated_items(self.tcx.parent(old_def_id))
|
||||
.filter_by_name_unhygienic(capitalized_name)
|
||||
.next()
|
||||
{
|
||||
(*item, segment)
|
||||
} else {
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
(*item, segment)
|
||||
}
|
||||
_ => return false,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -121,13 +121,12 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
len,
|
||||
)
|
||||
};
|
||||
if let Some(len) = len.try_to_target_usize(self.tcx()) {
|
||||
(len, ty)
|
||||
} else {
|
||||
let Some(len) = len.try_to_target_usize(self.tcx()) else {
|
||||
return Err(NonAsmTypeReason::UnevaluatedSIMDArrayLength(
|
||||
field.did, len,
|
||||
));
|
||||
}
|
||||
};
|
||||
(len, ty)
|
||||
}
|
||||
_ => (fields.len() as u64, elem_ty),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// tidy-alphabetical-start
|
||||
#![deny(clippy::manual_let_else)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
|
|
|
|||
|
|
@ -3543,10 +3543,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
span: Span,
|
||||
return_type: Option<Ty<'tcx>>,
|
||||
) {
|
||||
let output_ty = match self.err_ctxt().get_impl_future_output_ty(ty) {
|
||||
Some(output_ty) => self.resolve_vars_if_possible(output_ty),
|
||||
_ => return,
|
||||
};
|
||||
let Some(output_ty) = self.err_ctxt().get_impl_future_output_ty(ty) else { return };
|
||||
let output_ty = self.resolve_vars_if_possible(output_ty);
|
||||
let method_exists =
|
||||
self.method_exists_for_diagnostic(item_name, output_ty, call.hir_id, return_type);
|
||||
debug!("suggest_await_before_method: is_method_exist={}", method_exists);
|
||||
|
|
|
|||
|
|
@ -1072,11 +1072,8 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
|
|||
cx: &LateContext<'tcx>,
|
||||
expr: &hir::Expr<'_>,
|
||||
) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
|
||||
let def = if let hir::ExprKind::Path(ref qpath) = expr.kind {
|
||||
cx.qpath_res(qpath, expr.hir_id)
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
let hir::ExprKind::Path(ref qpath) = expr.kind else { return None };
|
||||
let def = cx.qpath_res(qpath, expr.hir_id);
|
||||
if let Res::Def(DefKind::Fn, did) = def {
|
||||
if !def_id_is_transmute(cx, did) {
|
||||
return None;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![deny(clippy::manual_let_else)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
|
|
|
|||
|
|
@ -120,10 +120,8 @@ impl Expr2024 {
|
|||
|
||||
fn check_ident_token(&mut self, cx: &crate::EarlyContext<'_>, token: &Token) {
|
||||
debug!("check_ident_token: {:?}", token);
|
||||
let (sym, edition) = match token.kind {
|
||||
TokenKind::Ident(sym, _) => (sym, Edition::Edition2024),
|
||||
_ => return,
|
||||
};
|
||||
let TokenKind::Ident(sym, _) = token.kind else { return };
|
||||
let edition = Edition::Edition2024;
|
||||
|
||||
debug!("token.span.edition(): {:?}", token.span.edition());
|
||||
if token.span.edition() >= edition {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#![allow(rustc::direct_use_of_rustc_type_ir)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![deny(clippy::manual_let_else)]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(associated_type_defaults)]
|
||||
|
|
|
|||
|
|
@ -706,12 +706,9 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
|
|||
| Bound(_, _)
|
||||
| Placeholder(_)
|
||||
| Error(_) => {
|
||||
if let Some(placeholder) = self.placeholder {
|
||||
// We replace these with infer (which is passed in from an infcx).
|
||||
placeholder
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
let Some(placeholder) = self.placeholder else { return Err(()) };
|
||||
// We replace these with infer (which is passed in from an infcx).
|
||||
placeholder
|
||||
}
|
||||
|
||||
Alias(Opaque, AliasTy { def_id, .. }) => {
|
||||
|
|
|
|||
|
|
@ -2395,9 +2395,7 @@ fn typetree_from_ty_impl_inner<'tcx>(
|
|||
}
|
||||
|
||||
if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() {
|
||||
let inner_ty = if let Some(inner) = ty.builtin_deref(true) {
|
||||
inner
|
||||
} else {
|
||||
let Some(inner_ty) = ty.builtin_deref(true) else {
|
||||
return TypeTree::new();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1528,18 +1528,13 @@ impl<'tcx> Ty<'tcx> {
|
|||
let mut cor_ty = self;
|
||||
let mut ty = cor_ty;
|
||||
loop {
|
||||
if let ty::Coroutine(def_id, args) = ty.kind() {
|
||||
cor_ty = ty;
|
||||
f(ty);
|
||||
if tcx.is_async_drop_in_place_coroutine(*def_id) {
|
||||
ty = args.first().unwrap().expect_ty();
|
||||
continue;
|
||||
} else {
|
||||
return cor_ty;
|
||||
}
|
||||
} else {
|
||||
let ty::Coroutine(def_id, args) = ty.kind() else { return cor_ty };
|
||||
cor_ty = ty;
|
||||
f(ty);
|
||||
if !tcx.is_async_drop_in_place_coroutine(*def_id) {
|
||||
return cor_ty;
|
||||
}
|
||||
ty = args.first().unwrap().expect_ty();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -100,11 +100,8 @@ impl<'tcx> MovePath<'tcx> {
|
|||
move_paths: &IndexSlice<MovePathIndex, MovePath<'_>>,
|
||||
f: impl Fn(MovePathIndex) -> bool,
|
||||
) -> Option<MovePathIndex> {
|
||||
let mut todo = if let Some(child) = self.first_child {
|
||||
vec![child]
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
let Some(child) = self.first_child else { return None };
|
||||
let mut todo = vec![child];
|
||||
|
||||
while let Some(mpi) = todo.pop() {
|
||||
if f(mpi) {
|
||||
|
|
@ -331,11 +328,10 @@ impl<'tcx> MovePathLookup<'tcx> {
|
|||
MoveSubPathResult::Stop => None,
|
||||
};
|
||||
|
||||
if let Some(&subpath) = subpath {
|
||||
result = subpath;
|
||||
} else {
|
||||
let Some(&subpath) = subpath else {
|
||||
return LookupResult::Parent(Some(result));
|
||||
}
|
||||
};
|
||||
result = subpath;
|
||||
}
|
||||
|
||||
LookupResult::Exact(result)
|
||||
|
|
|
|||
|
|
@ -721,11 +721,8 @@ impl<'tcx> Map<'tcx> {
|
|||
// Enum variant fields and enum discriminants alias each another.
|
||||
self.for_each_variant_sibling(index, sub, f);
|
||||
}
|
||||
if let Some(sub) = sub {
|
||||
index = sub
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
let Some(sub) = sub else { return };
|
||||
index = sub;
|
||||
}
|
||||
self.for_each_value_inside(index, f);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -590,31 +590,30 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
|
|||
let fields =
|
||||
fields.iter().map(|&f| self.eval_to_const(f)).collect::<Option<Vec<_>>>()?;
|
||||
let variant = if ty.ty.is_enum() { Some(variant) } else { None };
|
||||
if matches!(ty.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..))
|
||||
{
|
||||
let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?;
|
||||
let variant_dest = if let Some(variant) = variant {
|
||||
self.ecx.project_downcast(&dest, variant).discard_err()?
|
||||
} else {
|
||||
dest.clone()
|
||||
};
|
||||
for (field_index, op) in fields.into_iter().enumerate() {
|
||||
let field_dest = self
|
||||
.ecx
|
||||
.project_field(&variant_dest, FieldIdx::from_usize(field_index))
|
||||
.discard_err()?;
|
||||
self.ecx.copy_op(op, &field_dest).discard_err()?;
|
||||
}
|
||||
self.ecx
|
||||
.write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest)
|
||||
.discard_err()?;
|
||||
self.ecx
|
||||
.alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
|
||||
.discard_err()?;
|
||||
dest.into()
|
||||
} else {
|
||||
let (BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) = ty.backend_repr
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?;
|
||||
let variant_dest = if let Some(variant) = variant {
|
||||
self.ecx.project_downcast(&dest, variant).discard_err()?
|
||||
} else {
|
||||
dest.clone()
|
||||
};
|
||||
for (field_index, op) in fields.into_iter().enumerate() {
|
||||
let field_dest = self
|
||||
.ecx
|
||||
.project_field(&variant_dest, FieldIdx::from_usize(field_index))
|
||||
.discard_err()?;
|
||||
self.ecx.copy_op(op, &field_dest).discard_err()?;
|
||||
}
|
||||
self.ecx
|
||||
.write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest)
|
||||
.discard_err()?;
|
||||
self.ecx
|
||||
.alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
|
||||
.discard_err()?;
|
||||
dest.into()
|
||||
}
|
||||
Union(active_field, field) => {
|
||||
let field = self.eval_to_const(field)?;
|
||||
|
|
|
|||
|
|
@ -410,14 +410,8 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
// In theory, any zero-sized value could be borrowed
|
||||
// mutably without consequences. However, only &mut []
|
||||
// is allowed right now.
|
||||
if let ty::Array(_, len) = ty.kind() {
|
||||
match len.try_to_target_usize(self.tcx) {
|
||||
Some(0) => {}
|
||||
_ => return Err(Unpromotable),
|
||||
}
|
||||
} else {
|
||||
return Err(Unpromotable);
|
||||
}
|
||||
let ty::Array(_, len) = ty.kind() else { return Err(Unpromotable) };
|
||||
let Some(0) = len.try_to_target_usize(self.tcx) else { return Err(Unpromotable) };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -445,17 +445,15 @@ where
|
|||
goal_kind: ty::ClosureKind,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let cx = ecx.cx();
|
||||
let tupled_inputs_and_output =
|
||||
match structural_traits::extract_tupled_inputs_and_output_from_callable(
|
||||
let Some(tupled_inputs_and_output) =
|
||||
structural_traits::extract_tupled_inputs_and_output_from_callable(
|
||||
cx,
|
||||
goal.predicate.self_ty(),
|
||||
goal_kind,
|
||||
)? {
|
||||
Some(tupled_inputs_and_output) => tupled_inputs_and_output,
|
||||
None => {
|
||||
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
|
||||
}
|
||||
};
|
||||
)?
|
||||
else {
|
||||
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
|
||||
};
|
||||
let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output);
|
||||
|
||||
// A built-in `Fn` impl only holds if the output is sized.
|
||||
|
|
|
|||
|
|
@ -360,17 +360,15 @@ where
|
|||
}
|
||||
|
||||
let cx = ecx.cx();
|
||||
let tupled_inputs_and_output =
|
||||
match structural_traits::extract_tupled_inputs_and_output_from_callable(
|
||||
let Some(tupled_inputs_and_output) =
|
||||
structural_traits::extract_tupled_inputs_and_output_from_callable(
|
||||
cx,
|
||||
goal.predicate.self_ty(),
|
||||
goal_kind,
|
||||
)? {
|
||||
Some(a) => a,
|
||||
None => {
|
||||
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
|
||||
}
|
||||
};
|
||||
)?
|
||||
else {
|
||||
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
|
||||
};
|
||||
let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output);
|
||||
|
||||
// A built-in `Fn` impl only holds if the output is sized.
|
||||
|
|
@ -1409,42 +1407,39 @@ where
|
|||
let where_bounds: Vec<_> = candidates
|
||||
.extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_)))
|
||||
.collect();
|
||||
if let Some((response, info)) = self.try_merge_candidates(&where_bounds) {
|
||||
match info {
|
||||
// If there's an always applicable candidate, the result of all
|
||||
// other candidates does not matter. This means we can ignore
|
||||
// them when checking whether we've reached a fixpoint.
|
||||
//
|
||||
// We always prefer the first always applicable candidate, even if a
|
||||
// later candidate is also always applicable and would result in fewer
|
||||
// reruns. We could slightly improve this by e.g. searching for another
|
||||
// always applicable candidate which doesn't depend on any cycle heads.
|
||||
//
|
||||
// NOTE: This is optimization is observable in case there is an always
|
||||
// applicable global candidate and another non-global candidate which only
|
||||
// applies because of a provisional result. I can't even think of a test
|
||||
// case where this would occur and even then, this would not be unsound.
|
||||
// Supporting this makes the code more involved, so I am just going to
|
||||
// ignore this for now.
|
||||
MergeCandidateInfo::AlwaysApplicable(i) => {
|
||||
for (j, c) in where_bounds.into_iter().enumerate() {
|
||||
if i != j {
|
||||
self.ignore_candidate_head_usages(c.head_usages)
|
||||
}
|
||||
}
|
||||
// If a where-bound does not apply, we don't actually get a
|
||||
// candidate for it. We manually track the head usages
|
||||
// of all failed `ParamEnv` candidates instead.
|
||||
self.ignore_candidate_head_usages(
|
||||
failed_candidate_info.param_env_head_usages,
|
||||
);
|
||||
}
|
||||
MergeCandidateInfo::EqualResponse => {}
|
||||
}
|
||||
return Ok((response, Some(TraitGoalProvenVia::ParamEnv)));
|
||||
} else {
|
||||
let Some((response, info)) = self.try_merge_candidates(&where_bounds) else {
|
||||
return Ok((self.bail_with_ambiguity(&where_bounds), None));
|
||||
};
|
||||
match info {
|
||||
// If there's an always applicable candidate, the result of all
|
||||
// other candidates does not matter. This means we can ignore
|
||||
// them when checking whether we've reached a fixpoint.
|
||||
//
|
||||
// We always prefer the first always applicable candidate, even if a
|
||||
// later candidate is also always applicable and would result in fewer
|
||||
// reruns. We could slightly improve this by e.g. searching for another
|
||||
// always applicable candidate which doesn't depend on any cycle heads.
|
||||
//
|
||||
// NOTE: This is optimization is observable in case there is an always
|
||||
// applicable global candidate and another non-global candidate which only
|
||||
// applies because of a provisional result. I can't even think of a test
|
||||
// case where this would occur and even then, this would not be unsound.
|
||||
// Supporting this makes the code more involved, so I am just going to
|
||||
// ignore this for now.
|
||||
MergeCandidateInfo::AlwaysApplicable(i) => {
|
||||
for (j, c) in where_bounds.into_iter().enumerate() {
|
||||
if i != j {
|
||||
self.ignore_candidate_head_usages(c.head_usages)
|
||||
}
|
||||
}
|
||||
// If a where-bound does not apply, we don't actually get a
|
||||
// candidate for it. We manually track the head usages
|
||||
// of all failed `ParamEnv` candidates instead.
|
||||
self.ignore_candidate_head_usages(failed_candidate_info.param_env_head_usages);
|
||||
}
|
||||
MergeCandidateInfo::EqualResponse => {}
|
||||
}
|
||||
return Ok((response, Some(TraitGoalProvenVia::ParamEnv)));
|
||||
}
|
||||
|
||||
// Next, prefer any alias bound (nested or otherwise).
|
||||
|
|
|
|||
|
|
@ -1537,86 +1537,80 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
/// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
|
||||
fn restrict_assoc_type_in_where_clause(&self, span: Span, err: &mut Diag<'_>) -> bool {
|
||||
// Detect that we are actually in a `where` predicate.
|
||||
let (bounded_ty, bounds, where_span) = if let Some(ast::WherePredicate {
|
||||
let Some(ast::WherePredicate {
|
||||
kind:
|
||||
ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate {
|
||||
bounded_ty,
|
||||
bound_generic_params,
|
||||
bounds,
|
||||
}),
|
||||
span,
|
||||
span: where_span,
|
||||
..
|
||||
}) = self.diag_metadata.current_where_predicate
|
||||
{
|
||||
if !bound_generic_params.is_empty() {
|
||||
return false;
|
||||
}
|
||||
(bounded_ty, bounds, span)
|
||||
} else {
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
if !bound_generic_params.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Confirm that the target is an associated type.
|
||||
let (ty, _, path) = if let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind {
|
||||
// use this to verify that ident is a type param.
|
||||
let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else {
|
||||
return false;
|
||||
};
|
||||
if !matches!(
|
||||
partial_res.full_res(),
|
||||
Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
(&qself.ty, qself.position, path)
|
||||
} else {
|
||||
let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind else { return false };
|
||||
// use this to verify that ident is a type param.
|
||||
let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else { return false };
|
||||
if !matches!(
|
||||
partial_res.full_res(),
|
||||
Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let peeled_ty = qself.ty.peel_refs();
|
||||
let ast::TyKind::Path(None, type_param_path) = &peeled_ty.kind else { return false };
|
||||
// Confirm that the `SelfTy` is a type parameter.
|
||||
let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let peeled_ty = ty.peel_refs();
|
||||
if let ast::TyKind::Path(None, type_param_path) = &peeled_ty.kind {
|
||||
// Confirm that the `SelfTy` is a type parameter.
|
||||
let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else {
|
||||
if !matches!(
|
||||
partial_res.full_res(),
|
||||
Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
let ([ast::PathSegment { args: None, .. }], [ast::GenericBound::Trait(poly_trait_ref)]) =
|
||||
(&type_param_path.segments[..], &bounds[..])
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
let [ast::PathSegment { ident, args: None, id }] =
|
||||
&poly_trait_ref.trait_ref.path.segments[..]
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
if poly_trait_ref.modifiers != ast::TraitBoundModifiers::NONE {
|
||||
return false;
|
||||
}
|
||||
if ident.span == span {
|
||||
let Some(partial_res) = self.r.partial_res_map.get(&id) else {
|
||||
return false;
|
||||
};
|
||||
if !matches!(
|
||||
partial_res.full_res(),
|
||||
Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _))
|
||||
) {
|
||||
if !matches!(partial_res.full_res(), Some(hir::def::Res::Def(..))) {
|
||||
return false;
|
||||
}
|
||||
if let (
|
||||
[ast::PathSegment { args: None, .. }],
|
||||
[ast::GenericBound::Trait(poly_trait_ref)],
|
||||
) = (&type_param_path.segments[..], &bounds[..])
|
||||
&& let [ast::PathSegment { ident, args: None, id }] =
|
||||
&poly_trait_ref.trait_ref.path.segments[..]
|
||||
&& poly_trait_ref.modifiers == ast::TraitBoundModifiers::NONE
|
||||
{
|
||||
if ident.span == span {
|
||||
let Some(partial_res) = self.r.partial_res_map.get(&id) else {
|
||||
return false;
|
||||
};
|
||||
if !matches!(partial_res.full_res(), Some(hir::def::Res::Def(..))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let Some(new_where_bound_predicate) =
|
||||
mk_where_bound_predicate(path, poly_trait_ref, ty)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
*where_span,
|
||||
format!("constrain the associated type to `{ident}`"),
|
||||
where_bound_predicate_to_string(&new_where_bound_predicate),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
let Some(new_where_bound_predicate) =
|
||||
mk_where_bound_predicate(path, poly_trait_ref, &qself.ty)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
*where_span,
|
||||
format!("constrain the associated type to `{ident}`"),
|
||||
where_bound_predicate_to_string(&new_where_bound_predicate),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
false
|
||||
true
|
||||
}
|
||||
|
||||
/// Check if the source is call expression and the first argument is `self`. If true,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#![allow(internal_features)]
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
#![deny(clippy::manual_let_else)]
|
||||
#![feature(arbitrary_self_types)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue