Skip to content

Commit fd9bb7f

Browse files
committed
Auto merge of rust-lang#121003 - matthiaskrgr:rollup-u5wyztn, r=matthiaskrgr
Rollup of 10 pull requests Successful merges: - rust-lang#120696 (Properly handle `async` block and `async fn` in `if` exprs without `else`) - rust-lang#120751 (Provide more suggestions on invalid equality where bounds) - rust-lang#120802 (Bail out of drop elaboration when encountering error types) - rust-lang#120967 (docs: mention round-to-even in precision formatting) - rust-lang#120973 (allow static_mut_ref in some tests that specifically test mutable statics) - rust-lang#120974 (llvm-wrapper: adapt for LLVM API change: Add support for EXPORTAS name types) - rust-lang#120986 (iterator.rs: remove "Basic usage" text) - rust-lang#120987 (remove redundant logic) - rust-lang#120988 (fix comment) - rust-lang#120995 (PassWrapper: adapt for llvm/llvm-project@93cdd1b5cfa3735c) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 09d73fa + 70ea26d commit fd9bb7f

38 files changed

+611
-346
lines changed

compiler/rustc_ast_passes/src/ast_validation.rs

+89-35
Original file line numberDiff line numberDiff line change
@@ -1593,44 +1593,98 @@ fn deny_equality_constraints(
15931593
}
15941594
}
15951595
}
1596-
// Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1597-
if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1598-
if let [potential_param, potential_assoc] = &full_path.segments[..] {
1599-
for param in &generics.params {
1600-
if param.ident == potential_param.ident {
1601-
for bound in &param.bounds {
1602-
if let ast::GenericBound::Trait(trait_ref, TraitBoundModifiers::NONE) =
1603-
bound
1596+
1597+
let mut suggest =
1598+
|poly: &PolyTraitRef, potential_assoc: &PathSegment, predicate: &WhereEqPredicate| {
1599+
if let [trait_segment] = &poly.trait_ref.path.segments[..] {
1600+
let assoc = pprust::path_to_string(&ast::Path::from_ident(potential_assoc.ident));
1601+
let ty = pprust::ty_to_string(&predicate.rhs_ty);
1602+
let (args, span) = match &trait_segment.args {
1603+
Some(args) => match args.deref() {
1604+
ast::GenericArgs::AngleBracketed(args) => {
1605+
let Some(arg) = args.args.last() else {
1606+
return;
1607+
};
1608+
(format!(", {assoc} = {ty}"), arg.span().shrink_to_hi())
1609+
}
1610+
_ => return,
1611+
},
1612+
None => (format!("<{assoc} = {ty}>"), trait_segment.span().shrink_to_hi()),
1613+
};
1614+
let removal_span = if generics.where_clause.predicates.len() == 1 {
1615+
// We're removing th eonly where bound left, remove the whole thing.
1616+
generics.where_clause.span
1617+
} else {
1618+
let mut span = predicate.span;
1619+
let mut prev: Option<Span> = None;
1620+
let mut preds = generics.where_clause.predicates.iter().peekable();
1621+
// Find the predicate that shouldn't have been in the where bound list.
1622+
while let Some(pred) = preds.next() {
1623+
if let WherePredicate::EqPredicate(pred) = pred
1624+
&& pred.span == predicate.span
16041625
{
1605-
if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1606-
let assoc = pprust::path_to_string(&ast::Path::from_ident(
1607-
potential_assoc.ident,
1608-
));
1609-
let ty = pprust::ty_to_string(&predicate.rhs_ty);
1610-
let (args, span) = match &trait_segment.args {
1611-
Some(args) => match args.deref() {
1612-
ast::GenericArgs::AngleBracketed(args) => {
1613-
let Some(arg) = args.args.last() else {
1614-
continue;
1615-
};
1616-
(format!(", {assoc} = {ty}"), arg.span().shrink_to_hi())
1617-
}
1618-
_ => continue,
1619-
},
1620-
None => (
1621-
format!("<{assoc} = {ty}>"),
1622-
trait_segment.span().shrink_to_hi(),
1623-
),
1624-
};
1625-
err.assoc2 = Some(errors::AssociatedSuggestion2 {
1626-
span,
1627-
args,
1628-
predicate: predicate.span,
1629-
trait_segment: trait_segment.ident,
1630-
potential_assoc: potential_assoc.ident,
1631-
});
1626+
if let Some(next) = preds.peek() {
1627+
// This is the first predicate, remove the trailing comma as well.
1628+
span = span.with_hi(next.span().lo());
1629+
} else if let Some(prev) = prev {
1630+
// Remove the previous comma as well.
1631+
span = span.with_lo(prev.hi());
16321632
}
16331633
}
1634+
prev = Some(pred.span());
1635+
}
1636+
span
1637+
};
1638+
err.assoc2 = Some(errors::AssociatedSuggestion2 {
1639+
span,
1640+
args,
1641+
predicate: removal_span,
1642+
trait_segment: trait_segment.ident,
1643+
potential_assoc: potential_assoc.ident,
1644+
});
1645+
}
1646+
};
1647+
1648+
if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1649+
// Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1650+
for bounds in generics.params.iter().map(|p| &p.bounds).chain(
1651+
generics.where_clause.predicates.iter().filter_map(|pred| match pred {
1652+
WherePredicate::BoundPredicate(p) => Some(&p.bounds),
1653+
_ => None,
1654+
}),
1655+
) {
1656+
for bound in bounds {
1657+
if let GenericBound::Trait(poly, TraitBoundModifiers::NONE) = bound {
1658+
if full_path.segments[..full_path.segments.len() - 1]
1659+
.iter()
1660+
.map(|segment| segment.ident.name)
1661+
.zip(poly.trait_ref.path.segments.iter().map(|segment| segment.ident.name))
1662+
.all(|(a, b)| a == b)
1663+
&& let Some(potential_assoc) = full_path.segments.iter().last()
1664+
{
1665+
suggest(poly, potential_assoc, predicate);
1666+
}
1667+
}
1668+
}
1669+
}
1670+
// Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1671+
if let [potential_param, potential_assoc] = &full_path.segments[..] {
1672+
for (ident, bounds) in generics.params.iter().map(|p| (p.ident, &p.bounds)).chain(
1673+
generics.where_clause.predicates.iter().filter_map(|pred| match pred {
1674+
WherePredicate::BoundPredicate(p)
1675+
if let ast::TyKind::Path(None, path) = &p.bounded_ty.kind
1676+
&& let [segment] = &path.segments[..] =>
1677+
{
1678+
Some((segment.ident, &p.bounds))
1679+
}
1680+
_ => None,
1681+
}),
1682+
) {
1683+
if ident == potential_param.ident {
1684+
for bound in bounds {
1685+
if let ast::GenericBound::Trait(poly, TraitBoundModifiers::NONE) = bound {
1686+
suggest(poly, potential_assoc, predicate);
1687+
}
16341688
}
16351689
}
16361690
}

compiler/rustc_hir_typeck/src/coercion.rs

+28-7
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,11 @@ struct CollectRetsVisitor<'tcx> {
9898

9999
impl<'tcx> Visitor<'tcx> for CollectRetsVisitor<'tcx> {
100100
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
101-
if let hir::ExprKind::Ret(_) = expr.kind {
102-
self.ret_exprs.push(expr);
101+
match expr.kind {
102+
hir::ExprKind::Ret(_) => self.ret_exprs.push(expr),
103+
// `return` in closures does not return from the outer function
104+
hir::ExprKind::Closure(_) => return,
105+
_ => {}
103106
}
104107
intravisit::walk_expr(self, expr);
105108
}
@@ -1845,13 +1848,31 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
18451848
}
18461849

18471850
let parent_id = fcx.tcx.hir().get_parent_item(id);
1848-
let parent_item = fcx.tcx.hir_node_by_def_id(parent_id.def_id);
1851+
let mut parent_item = fcx.tcx.hir_node_by_def_id(parent_id.def_id);
1852+
// When suggesting return, we need to account for closures and async blocks, not just items.
1853+
for (_, node) in fcx.tcx.hir().parent_iter(id) {
1854+
match node {
1855+
hir::Node::Expr(&hir::Expr {
1856+
kind: hir::ExprKind::Closure(hir::Closure { .. }),
1857+
..
1858+
}) => {
1859+
parent_item = node;
1860+
break;
1861+
}
1862+
hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => break,
1863+
_ => {}
1864+
}
1865+
}
18491866

1850-
if let (Some(expr), Some(_), Some((fn_id, fn_decl, _, _))) =
1851-
(expression, blk_id, fcx.get_node_fn_decl(parent_item))
1852-
{
1867+
if let (Some(expr), Some(_), Some(fn_decl)) = (expression, blk_id, parent_item.fn_decl()) {
18531868
fcx.suggest_missing_break_or_return_expr(
1854-
&mut err, expr, fn_decl, expected, found, id, fn_id,
1869+
&mut err,
1870+
expr,
1871+
fn_decl,
1872+
expected,
1873+
found,
1874+
id,
1875+
parent_id.into(),
18551876
);
18561877
}
18571878

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+29-8
Original file line numberDiff line numberDiff line change
@@ -963,14 +963,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
963963
owner_id,
964964
..
965965
}) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, false)),
966-
Node::Expr(&hir::Expr { hir_id, kind: hir::ExprKind::Closure(..), .. })
967-
if let Node::Item(&hir::Item {
968-
ident,
969-
kind: hir::ItemKind::Fn(ref sig, ..),
970-
owner_id,
971-
..
972-
}) = self.tcx.parent_hir_node(hir_id) =>
973-
{
966+
Node::Expr(&hir::Expr {
967+
hir_id,
968+
kind:
969+
hir::ExprKind::Closure(hir::Closure {
970+
kind: hir::ClosureKind::Coroutine(..), ..
971+
}),
972+
..
973+
}) => {
974+
let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
975+
Node::Item(&hir::Item {
976+
ident,
977+
kind: hir::ItemKind::Fn(ref sig, ..),
978+
owner_id,
979+
..
980+
}) => (ident, sig, owner_id),
981+
Node::TraitItem(&hir::TraitItem {
982+
ident,
983+
kind: hir::TraitItemKind::Fn(ref sig, ..),
984+
owner_id,
985+
..
986+
}) => (ident, sig, owner_id),
987+
Node::ImplItem(&hir::ImplItem {
988+
ident,
989+
kind: hir::ImplItemKind::Fn(ref sig, ..),
990+
owner_id,
991+
..
992+
}) => (ident, sig, owner_id),
993+
_ => return None,
994+
};
974995
Some((
975996
hir::HirId::make_owner(owner_id.def_id),
976997
&sig.decl,

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1726,7 +1726,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17261726
}
17271727

17281728
/// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
1729-
fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
1729+
pub(crate) fn get_parent_fn_decl(
1730+
&self,
1731+
blk_id: hir::HirId,
1732+
) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
17301733
let parent = self.tcx.hir_node_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id);
17311734
self.get_node_fn_decl(parent).map(|(_, fn_decl, ident, _)| (fn_decl, ident))
17321735
}

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+56-26
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
827827
}
828828
hir::FnRetTy::Return(hir_ty) => {
829829
if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind
830+
// FIXME: account for RPITIT.
830831
&& let hir::Node::Item(hir::Item {
831832
kind: hir::ItemKind::OpaqueTy(op_ty), ..
832833
}) = self.tcx.hir_node(item_id.hir_id())
@@ -1038,33 +1039,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10381039
return;
10391040
}
10401041

1041-
if let hir::FnRetTy::Return(ty) = fn_decl.output {
1042-
let ty = self.astconv().ast_ty_to_ty(ty);
1043-
let bound_vars = self.tcx.late_bound_vars(fn_id);
1044-
let ty = self
1045-
.tcx
1046-
.instantiate_bound_regions_with_erased(Binder::bind_with_vars(ty, bound_vars));
1047-
let ty = match self.tcx.asyncness(fn_id.owner) {
1048-
ty::Asyncness::Yes => self.get_impl_future_output_ty(ty).unwrap_or_else(|| {
1049-
span_bug!(fn_decl.output.span(), "failed to get output type of async function")
1050-
}),
1051-
ty::Asyncness::No => ty,
1052-
};
1053-
let ty = self.normalize(expr.span, ty);
1054-
if self.can_coerce(found, ty) {
1055-
if let Some(owner_node) = self.tcx.hir_node(fn_id).as_owner()
1056-
&& let Some(span) = expr.span.find_ancestor_inside(*owner_node.span())
1057-
{
1058-
err.multipart_suggestion(
1059-
"you might have meant to return this value",
1060-
vec![
1061-
(span.shrink_to_lo(), "return ".to_string()),
1062-
(span.shrink_to_hi(), ";".to_string()),
1063-
],
1064-
Applicability::MaybeIncorrect,
1065-
);
1066-
}
1042+
let scope = self
1043+
.tcx
1044+
.hir()
1045+
.parent_iter(id)
1046+
.filter(|(_, node)| {
1047+
matches!(
1048+
node,
1049+
Node::Expr(Expr { kind: ExprKind::Closure(..), .. })
1050+
| Node::Item(_)
1051+
| Node::TraitItem(_)
1052+
| Node::ImplItem(_)
1053+
)
1054+
})
1055+
.next();
1056+
let in_closure =
1057+
matches!(scope, Some((_, Node::Expr(Expr { kind: ExprKind::Closure(..), .. }))));
1058+
1059+
let can_return = match fn_decl.output {
1060+
hir::FnRetTy::Return(ty) => {
1061+
let ty = self.astconv().ast_ty_to_ty(ty);
1062+
let bound_vars = self.tcx.late_bound_vars(fn_id);
1063+
let ty = self
1064+
.tcx
1065+
.instantiate_bound_regions_with_erased(Binder::bind_with_vars(ty, bound_vars));
1066+
let ty = match self.tcx.asyncness(fn_id.owner) {
1067+
ty::Asyncness::Yes => self.get_impl_future_output_ty(ty).unwrap_or_else(|| {
1068+
span_bug!(
1069+
fn_decl.output.span(),
1070+
"failed to get output type of async function"
1071+
)
1072+
}),
1073+
ty::Asyncness::No => ty,
1074+
};
1075+
let ty = self.normalize(expr.span, ty);
1076+
self.can_coerce(found, ty)
1077+
}
1078+
hir::FnRetTy::DefaultReturn(_) if in_closure => {
1079+
self.ret_coercion.as_ref().map_or(false, |ret| {
1080+
let ret_ty = ret.borrow().expected_ty();
1081+
self.can_coerce(found, ret_ty)
1082+
})
10671083
}
1084+
_ => false,
1085+
};
1086+
if can_return
1087+
&& let Some(owner_node) = self.tcx.hir_node(fn_id).as_owner()
1088+
&& let Some(span) = expr.span.find_ancestor_inside(*owner_node.span())
1089+
{
1090+
err.multipart_suggestion(
1091+
"you might have meant to return this value",
1092+
vec![
1093+
(span.shrink_to_lo(), "return ".to_string()),
1094+
(span.shrink_to_hi(), ";".to_string()),
1095+
],
1096+
Applicability::MaybeIncorrect,
1097+
);
10681098
}
10691099
}
10701100

compiler/rustc_hir_typeck/src/method/suggest.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -1073,12 +1073,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10731073
// for instance
10741074
self.tcx.at(span).type_of(*def_id).instantiate_identity()
10751075
!= rcvr_ty
1076-
&& self
1077-
.tcx
1078-
.at(span)
1079-
.type_of(*def_id)
1080-
.instantiate_identity()
1081-
!= rcvr_ty
10821076
}
10831077
(Mode::Path, false, _) => true,
10841078
_ => false,
@@ -1092,7 +1086,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10921086
inherent_impls_candidate.sort();
10931087
inherent_impls_candidate.dedup();
10941088

1095-
// number of type to shows at most.
1089+
// number of types to show at most
10961090
let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
10971091
let type_candidates = inherent_impls_candidate
10981092
.iter()

0 commit comments

Comments
 (0)