Skip to content

Rollup of 8 pull requests #106198

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
321247d
Share testing utilities with non-btree test cases
ssomers Feb 18, 2022
204f854
Slightly tighten leak-on-panic test cases
ssomers Feb 18, 2022
a80e685
Test leaking of BinaryHeap Drain iterators
ssomers Feb 18, 2022
d2eb2bb
Clarify docs of `RefCell`
ChayimFriedman2 Nov 2, 2022
3b8b0ac
Fix unused_must_use warning for Box::from_raw
noeddl Nov 5, 2022
70bba3b
rustdoc: Fix backoff doc to match implementation
jonasspinner Nov 22, 2022
1b341fe
Suggest `impl Iterator` when possible for `_` return type
estebank Dec 27, 2022
43b2486
Clean up operator type checking
compiler-errors Dec 27, 2022
8bf7ec7
Deduplicate more op-flavored methods
compiler-errors Dec 27, 2022
aff403c
Recover `fn` keyword as `Fn` trait in bounds
compiler-errors Dec 27, 2022
6d332c4
Fix `core::any` mod-level docs
albertlarsan68 Dec 27, 2022
df2a35e
review comments
estebank Dec 27, 2022
b400bde
Shorten type in note
estebank Dec 27, 2022
05f567a
Rollup merge of #94145 - ssomers:binary_heap_tests, r=jyn514
matthiaskrgr Dec 28, 2022
4894b2a
Rollup merge of #103881 - ChayimFriedman2:patch-2, r=compiler-errors
matthiaskrgr Dec 28, 2022
b583fc8
Rollup merge of #104024 - noeddl:unused-must-use, r=compiler-errors
matthiaskrgr Dec 28, 2022
d713ad2
Rollup merge of #104708 - jonasspinner:fix-backoff-doc-to-match-imple…
matthiaskrgr Dec 28, 2022
8d2c93e
Rollup merge of #106172 - estebank:suggest-impl-trait, r=compiler-errors
matthiaskrgr Dec 28, 2022
5421b60
Rollup merge of #106173 - compiler-errors:deduplicate-op-methods, r=j…
matthiaskrgr Dec 28, 2022
d3d59db
Rollup merge of #106176 - compiler-errors:fn-kw-as-fn-trait, r=estebank
matthiaskrgr Dec 28, 2022
e28916b
Rollup merge of #106184 - albertlarsan68:docs-106154, r=Nilstrieb
matthiaskrgr Dec 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/parse.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -365,3 +365,6 @@ parse_invalid_identifier_with_leading_number = expected identifier, found number

parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn`
.suggestion = replace `fn` with `impl` here

parse_expected_fn_path_found_fn_keyword = expected identifier, found keyword `fn`
.suggestion = use `Fn` to refer to the trait
2 changes: 1 addition & 1 deletion compiler/rustc_expand/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ impl<'a> ExtCtxt<'a> {

// Builds `#[name = val]`.
//
// Note: `span` is used for both the identifer and the value.
// Note: `span` is used for both the identifier and the value.
pub fn attr_name_value_str(&self, name: Symbol, val: Symbol, span: Span) -> ast::Attribute {
let g = &self.sess.parse_sess.attr_id_generator;
attr::mk_attr_name_value_str(g, ast::AttrStyle::Outer, name, val, span)
Expand Down
61 changes: 60 additions & 1 deletion compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,18 @@ use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericParamKind, Node};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::util::{Discr, IntTypeExt};
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use rustc_target::spec::abi;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use rustc_trait_selection::traits::ObligationCtxt;
use std::iter;

mod generics_of;
Expand Down Expand Up @@ -1224,7 +1228,17 @@ fn infer_return_ty_for_fn_sig<'tcx>(
// to prevent the user from getting a papercut while trying to use the unique closure
// syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html");
diag.note(
"for more information on `Fn` traits and closure types, see \
https://doc.rust-lang.org/book/ch13-01-closures.html",
);
} else if let Some(i_ty) = suggest_impl_iterator(tcx, ret_ty, ty.span, hir_id, def_id) {
diag.span_suggestion(
ty.span,
"replace with an appropriate return type",
format!("impl Iterator<Item = {}>", i_ty),
Applicability::MachineApplicable,
);
}
diag.emit();

Expand All @@ -1242,6 +1256,51 @@ fn infer_return_ty_for_fn_sig<'tcx>(
}
}

fn suggest_impl_iterator<'tcx>(
tcx: TyCtxt<'tcx>,
ret_ty: Ty<'tcx>,
span: Span,
hir_id: hir::HirId,
def_id: LocalDefId,
) -> Option<Ty<'tcx>> {
let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) else { return None; };
let Some(iterator_item) = tcx.get_diagnostic_item(sym::IteratorItem) else { return None; };
if !tcx
.infer_ctxt()
.build()
.type_implements_trait(iter_trait, [ret_ty], tcx.param_env(def_id))
.must_apply_modulo_regions()
{
return None;
}
let infcx = tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new_in_snapshot(&infcx);
// Find the type of `Iterator::Item`.
let origin = TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span };
let ty_var = infcx.next_ty_var(origin);
let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection(
ty::ProjectionPredicate {
projection_ty: tcx.mk_alias_ty(iterator_item, tcx.mk_substs([ret_ty.into()].iter())),
term: ty_var.into(),
},
)));
// Add `<ret_ty as Iterator>::Item = _` obligation.
ocx.register_obligation(crate::traits::Obligation::misc(
tcx,
span,
hir_id,
tcx.param_env(def_id),
projection,
));
if ocx.select_where_possible().is_empty()
&& let item_ty = infcx.resolve_vars_if_possible(ty_var)
&& item_ty.is_suggestable(tcx, false)
{
return Some(item_ty);
}
None
}

fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
let icx = ItemCtxt::new(tcx, def_id);
let item = tcx.hir().expect_item(def_id.expect_local());
Expand Down
13 changes: 7 additions & 6 deletions compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use rustc_hir::intravisit;
use rustc_hir::intravisit::Visitor;
use rustc_hir::{HirId, Node};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable};
Expand Down Expand Up @@ -907,10 +908,10 @@ fn infer_placeholder_type<'a>(
Applicability::MachineApplicable,
);
} else {
err.span_note(
with_forced_trimmed_paths!(err.span_note(
tcx.hir().body(body_id).value.span,
&format!("however, the inferred type `{}` cannot be named", ty),
);
&format!("however, the inferred type `{ty}` cannot be named"),
));
}
}

Expand All @@ -931,10 +932,10 @@ fn infer_placeholder_type<'a>(
Applicability::MaybeIncorrect,
);
} else {
diag.span_note(
with_forced_trimmed_paths!(diag.span_note(
tcx.hir().body(body_id).value.span,
&format!("however, the inferred type `{}` cannot be named", ty),
);
&format!("however, the inferred type `{ty}` cannot be named"),
));
}
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});

if let Some(ok) = self.lookup_method_in_trait(
call_expr.span,
self.misc(call_expr.span),
method_name,
trait_def_id,
adjusted_ty,
Expand Down
140 changes: 18 additions & 122 deletions compiler/rustc_hir_typeck/src/method/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub use self::suggest::SelfSource;
pub use self::MethodError::*;

use crate::errors::OpMethodGenericParams;
use crate::{Expectation, FnCtxt};
use crate::FnCtxt;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
Expand Down Expand Up @@ -264,7 +264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

pub(super) fn obligation_for_method(
&self,
span: Span,
cause: ObligationCause<'tcx>,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>,
Expand All @@ -282,71 +282,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
self.var_for_def(span, param)
});

let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);

// Construct an obligation
let poly_trait_ref = ty::Binder::dummy(trait_ref);
(
traits::Obligation::misc(
self.tcx,
span,
self.body_id,
self.param_env,
poly_trait_ref.without_const(),
),
substs,
)
}

pub(super) fn obligation_for_op_method(
&self,
span: Span,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_type: Option<Ty<'tcx>>,
opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
expected: Expectation<'tcx>,
) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>)
{
// Construct a trait-reference `self_ty : Trait<input_tys>`
let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
match param.kind {
GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {}
GenericParamDefKind::Type { .. } => {
if param.index == 0 {
return self_ty.into();
} else if let Some(input_type) = opt_input_type {
return input_type.into();
}
}
}
self.var_for_def(span, param)
self.var_for_def(cause.span, param)
});

let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);

// Construct an obligation
let poly_trait_ref = ty::Binder::dummy(trait_ref);
let output_ty = expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty));

(
traits::Obligation::new(
self.tcx,
traits::ObligationCause::new(
span,
self.body_id,
traits::BinOp {
rhs_span: opt_input_expr.map(|expr| expr.span),
is_lit: opt_input_expr
.map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
output_ty,
},
),
cause,
self.param_env,
poly_trait_ref,
poly_trait_ref.without_const(),
),
substs,
)
Expand All @@ -357,69 +305,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// In particular, it doesn't really do any probing: it simply constructs
/// an obligation for a particular trait with the given self type and checks
/// whether that trait is implemented.
#[instrument(level = "debug", skip(self, span))]
#[instrument(level = "debug", skip(self))]
pub(super) fn lookup_method_in_trait(
&self,
span: Span,
cause: ObligationCause<'tcx>,
m_name: Ident,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
let (obligation, substs) =
self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types);
self.construct_obligation_for_trait(
span,
m_name,
trait_def_id,
obligation,
substs,
None,
false,
)
}

pub(super) fn lookup_op_method_in_trait(
&self,
span: Span,
m_name: Ident,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_type: Option<Ty<'tcx>>,
opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
expected: Expectation<'tcx>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
let (obligation, substs) = self.obligation_for_op_method(
span,
trait_def_id,
self_ty,
opt_input_type,
opt_input_expr,
expected,
);
self.construct_obligation_for_trait(
span,
m_name,
trait_def_id,
obligation,
substs,
opt_input_expr,
true,
)
self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types);
self.construct_obligation_for_trait(m_name, trait_def_id, obligation, substs)
}

// FIXME(#18741): it seems likely that we can consolidate some of this
// code with the other method-lookup code. In particular, the second half
// of this method is basically the same as confirmation.
fn construct_obligation_for_trait(
&self,
span: Span,
m_name: Ident,
trait_def_id: DefId,
obligation: traits::PredicateObligation<'tcx>,
substs: &'tcx ty::List<ty::subst::GenericArg<'tcx>>,
opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
is_op: bool,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
debug!(?obligation);

Expand All @@ -435,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tcx = self.tcx;
let Some(method_item) = self.associated_value(trait_def_id, m_name) else {
tcx.sess.delay_span_bug(
span,
obligation.cause.span,
"operator trait does not have corresponding operator method",
);
return None;
Expand All @@ -461,24 +369,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// with bound regions.
let fn_sig = tcx.bound_fn_sig(def_id);
let fn_sig = fn_sig.subst(self.tcx, substs);
let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig);

let cause = if is_op {
ObligationCause::new(
span,
self.body_id,
traits::BinOp {
rhs_span: opt_input_expr.map(|expr| expr.span),
is_lit: opt_input_expr
.map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
output_ty: None,
},
)
} else {
traits::ObligationCause::misc(span, self.body_id)
};
let fn_sig =
self.replace_bound_vars_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);

let InferOk { value, obligations: o } = self.at(&cause, self.param_env).normalize(fn_sig);
let InferOk { value, obligations: o } =
self.at(&obligation.cause, self.param_env).normalize(fn_sig);
let fn_sig = {
obligations.extend(o);
value
Expand All @@ -494,15 +389,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// any late-bound regions appearing in its bounds.
let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs);

let InferOk { value, obligations: o } = self.at(&cause, self.param_env).normalize(bounds);
let InferOk { value, obligations: o } =
self.at(&obligation.cause, self.param_env).normalize(bounds);
let bounds = {
obligations.extend(o);
value
};

assert!(!bounds.has_escaping_bound_vars());

let predicates_cause = cause.clone();
let predicates_cause = obligation.cause.clone();
obligations.extend(traits::predicates_for_generics(
move |_, _| predicates_cause.clone(),
self.param_env,
Expand All @@ -517,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
obligations.push(traits::Obligation::new(
tcx,
cause,
obligation.cause,
self.param_env,
ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())),
));
Expand Down
Loading