Skip to content
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

Account for late-bound lifetimes in generics #103448

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 11 additions & 9 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2359,8 +2359,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// If a closure captured our `target` and then assigned
// into a place then we should annotate the closure in
// case it ends up being assigned into the return place.
annotated_closure =
self.annotate_fn_sig(def_id, substs.as_closure().sig());
annotated_closure = self.annotate_fn_sig(
def_id,
substs.as_closure().sig().skip_binder(),
);
debug!(
"annotate_argument_and_return_for_borrow: \
annotated_closure={:?} assigned_from_local={:?} \
Expand Down Expand Up @@ -2483,7 +2485,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn annotate_fn_sig(
&self,
did: LocalDefId,
sig: ty::PolyFnSig<'tcx>,
sig: ty::FnSig<'tcx>,
) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
let is_closure = self.infcx.tcx.is_closure(did.to_def_id());
Expand Down Expand Up @@ -2513,12 +2515,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// 3. The return type is not a reference. In this case, we don't highlight
// anything.
let return_ty = sig.output();
match return_ty.skip_binder().kind() {
match return_ty.kind() {
ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => {
// This is case 1 from above, return type is a named reference so we need to
// search for relevant arguments.
let mut arguments = Vec::new();
for (index, argument) in sig.inputs().skip_binder().iter().enumerate() {
for (index, argument) in sig.inputs().iter().enumerate() {
if let ty::Ref(argument_region, _, _) = argument.kind() {
if argument_region == return_region {
// Need to use the `rustc_middle::ty` types to compare against the
Expand All @@ -2542,7 +2544,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {

// We use a mix of the HIR and the Ty types to get information
// as the HIR doesn't have full types for closure arguments.
let return_ty = sig.output().skip_binder();
let return_ty = sig.output();
let mut return_span = fn_decl.output.span();
if let hir::FnRetTy::Return(ty) = &fn_decl.output {
if let hir::TyKind::Rptr(lifetime, _) = ty.kind {
Expand All @@ -2561,7 +2563,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// reference so we select
// the first argument.
let argument_span = fn_decl.inputs.first()?.span;
let argument_ty = sig.inputs().skip_binder().first()?;
let argument_ty = sig.inputs().first()?;

// Closure arguments are wrapped in a tuple, so we need to get the first
// from that.
Expand All @@ -2581,10 +2583,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// This is also case 2 from above but for functions, return type is still an
// anonymous reference so we select the first argument.
let argument_span = fn_decl.inputs.first()?.span;
let argument_ty = *sig.inputs().skip_binder().first()?;
let argument_ty = *sig.inputs().first()?;

let return_span = fn_decl.output.span();
let return_ty = sig.output().skip_binder();
let return_ty = sig.output();

// We expect the first argument to be a reference.
match argument_ty.kind() {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/universal_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
// C-variadic fns also have a `VaList` input that's not listed in the signature
// (as it's created inside the body itself, not passed in from outside).
if let DefiningTy::FnDef(def_id, _) = defining_ty {
if self.infcx.tcx.fn_sig(def_id).c_variadic() {
if self.infcx.tcx.fn_sig(def_id).c_variadic {
let va_list_did = self.infcx.tcx.require_lang_item(
LangItem::VaList,
Some(self.infcx.tcx.def_span(self.mir_def.did)),
Expand Down Expand Up @@ -652,7 +652,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
DefiningTy::FnDef(def_id, _) => {
let sig = tcx.fn_sig(def_id);
let sig = indices.fold_to_region_vids(tcx, sig);
sig.inputs_and_output()
ty::Binder::dummy(sig.inputs_and_output)
}

DefiningTy::Const(def_id, _) => {
Expand Down
5 changes: 1 addition & 4 deletions compiler/rustc_codegen_cranelift/src/main_shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,7 @@ pub(crate) fn maybe_create_entry_wrapper(
// late-bound regions, since late-bound
// regions must appear in the argument
// listing.
let main_ret_ty = tcx.normalize_erasing_regions(
ty::ParamEnv::reveal_all(),
main_ret_ty.no_bound_vars().unwrap(),
);
let main_ret_ty = tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), main_ret_ty);

let cmain_sig = Signature {
params: vec![
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
// the WebAssembly specification, which has this feature. This won't be
// needed when LLVM enables this `multivalue` feature by default.
if !cx.tcx.is_closure(instance.def_id()) {
let abi = cx.tcx.fn_sig(instance.def_id()).abi();
let abi = cx.tcx.fn_sig(instance.def_id()).abi;
if abi == Abi::Wasm {
function_features.push("+multivalue".to_string());
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: DefId) -> Instance<
let instance = Instance::new(
def_id,
InternalSubsts::for_item(tcx, def_id, |param, _| {
if let ty::GenericParamDefKind::Lifetime = param.kind {
if let ty::GenericParamDefKind::Lifetime { .. } = param.kind {
tcx.lifetimes.re_erased.into()
} else {
tcx.mk_param_from_def(param)
Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,10 +445,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// late-bound regions, since late-bound
// regions must appear in the argument
// listing.
let main_ret_ty = cx.tcx().normalize_erasing_regions(
ty::ParamEnv::reveal_all(),
main_ret_ty.no_bound_vars().unwrap(),
);
let main_ret_ty =
cx.tcx().normalize_erasing_regions(ty::ParamEnv::reveal_all(), main_ret_ty);

let Some(llfn) = cx.declare_c_main(llfty) else {
// FIXME: We should be smart and show a better diagnostic here.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/const_eval/fn_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
if cfg!(debug_assertions) && stab.promotable {
let sig = tcx.fn_sig(def_id);
assert_eq!(
sig.unsafety(),
sig.unsafety,
hir::Unsafety::Normal,
"don't mark const unsafe fns as promotable",
// https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
*self.tcx,
ty::ParamEnv::reveal_all(),
const_panic_fmt,
self.tcx.intern_substs(&[]),
self.tcx.intern_substs(&[self.tcx.lifetimes.re_erased.into()]),
)
.unwrap()
.unwrap(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {

fn path_generic_args(
mut self,
_: bool,
print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
args: &[GenericArg<'tcx>],
) -> Result<Self::Path, Self::Error> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
// instead of the type of the return place.
self.span = body.local_decls[RETURN_PLACE].source_info.span;
let return_ty = tcx.fn_sig(def_id).output();
self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE);
self.check_local_or_return_ty(return_ty, RETURN_PLACE);
}

if !tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) {
Expand Down
18 changes: 17 additions & 1 deletion compiler/rustc_const_eval/src/transform/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,23 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
TerminatorKind::Call { func, args, destination, target, cleanup, .. } => {
let func_ty = func.ty(&self.body.local_decls, self.tcx);
match func_ty.kind() {
ty::FnPtr(..) | ty::FnDef(..) => {}
ty::FnPtr(..) => {}
ty::FnDef(def_id, substs) => {
if cfg!(debug_assertions) {
debug!(?def_id, ?substs);
let generics = self.tcx.generics_of(def_id);
debug_assert_eq!(generics.count(), substs.len());
let fn_sig = self.tcx.bound_fn_sig(*def_id);
let _ = fn_sig.subst(self.tcx, *substs);
for arg in substs.iter() {
if let ty::GenericArgKind::Lifetime(lt) = arg.unpack()
&& lt != self.tcx.lifetimes.re_erased
{
panic!("{substs:?} contains non-erased lifetimes");
}
}
}
}
_ => self.fail(
location,
format!("encountered non-callable type {} in `Call` terminator", func_ty),
Expand Down
51 changes: 26 additions & 25 deletions compiler/rustc_hir_analysis/src/astconv/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::astconv::{
use crate::errors::AssocTypeBindingNotAllowed;
use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs};
use rustc_ast::ast::ParamKindOrd;
use rustc_errors::{struct_span_err, Applicability, Diagnostic, MultiSpan};
use rustc_errors::{struct_span_err, Applicability, Diagnostic};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
Expand All @@ -15,7 +15,6 @@ use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::ty::{
self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt,
};
use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
use rustc_span::{symbol::kw, Span};
use smallvec::SmallVec;

Expand Down Expand Up @@ -255,7 +254,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
match (args.peek(), params.peek()) {
(Some(&arg), Some(&param)) => {
match (arg, &param.kind, arg_count.explicit_late_bound) {
(GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _)
(GenericArg::Lifetime(_), GenericParamDefKind::Lifetime { .. }, _)
| (
GenericArg::Type(_) | GenericArg::Infer(_),
GenericParamDefKind::Type { .. },
Expand All @@ -272,7 +271,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
(
GenericArg::Infer(_) | GenericArg::Type(_) | GenericArg::Const(_),
GenericParamDefKind::Lifetime,
GenericParamDefKind::Lifetime { .. },
_,
) => {
// We expected a lifetime argument, but got a type or const
Expand Down Expand Up @@ -623,36 +622,38 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
args: &hir::GenericArgs<'_>,
position: GenericArgPosition,
) -> ExplicitLateBound {
let param_counts = def.own_counts();
let infer_lifetimes = position != GenericArgPosition::Type && !args.has_lifetime_params();

if infer_lifetimes {
return ExplicitLateBound::No;
}

if let Some(span_late) = def.has_late_bound_regions {
let has_late_bound_regions = def
.params
.iter()
.find(|param| {
matches!(param.kind, ty::GenericParamDefKind::Lifetime { late_bound: true })
})
.map(|param| tcx.def_span(param.def_id));

if let Some(span_late) = has_late_bound_regions {
let msg = "cannot specify lifetime arguments explicitly \
if late bound lifetime parameters are present";
let note = "the late bound lifetime parameter is introduced here";
let span = args.args[0].span();

if position == GenericArgPosition::Value
&& args.num_lifetime_params() != param_counts.lifetimes
{
let mut err = tcx.sess.struct_span_err(span, msg);
err.span_note(span_late, note);
err.emit();
} else {
let mut multispan = MultiSpan::from_span(span);
multispan.push_span_label(span_late, note);
tcx.struct_span_lint_hir(
LATE_BOUND_LIFETIME_ARGUMENTS,
args.args[0].hir_id(),
multispan,
msg,
|lint| lint,
);
}
let help = format!(
"remove the explicit lifetime argument{}",
rustc_errors::pluralize!(args.num_lifetime_params())
);
let spans: Vec<_> = args
.args
.iter()
.filter_map(|arg| match arg {
hir::GenericArg::Lifetime(l) => Some(l.span),
_ => None,
})
.collect();

tcx.sess.struct_span_err(spans, msg).span_note(span_late, note).help(help).emit();

ExplicitLateBound::Yes
} else {
Expand Down
11 changes: 5 additions & 6 deletions compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};

match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
(GenericParamDefKind::Lifetime { .. }, GenericArg::Lifetime(lt)) => {
self.astconv.ast_region_to_region(lt, Some(param)).into()
}
(&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
Expand Down Expand Up @@ -458,7 +458,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) -> subst::GenericArg<'tcx> {
let tcx = self.astconv.tcx();
match param.kind {
GenericParamDefKind::Lifetime => self
GenericParamDefKind::Lifetime { .. } => self
.astconv
.re_infer(Some(param), self.span)
.unwrap_or_else(|| {
Expand Down Expand Up @@ -2720,7 +2720,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let substs = InternalSubsts::for_item(tcx, def_id, |param, _| {
if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) {
// Our own parameters are the resolved lifetimes.
if let GenericParamDefKind::Lifetime = param.kind {
if let GenericParamDefKind::Lifetime { .. } = param.kind {
if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] {
self.ast_region_to_region(lifetime, None).into()
} else {
Expand All @@ -2739,7 +2739,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// For `impl Trait` in the types of statics, constants,
// locals and type aliases. These capture all parent
// lifetimes, so they can use their identity subst.
GenericParamDefKind::Lifetime
GenericParamDefKind::Lifetime { .. }
if matches!(
origin,
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..)
Expand Down Expand Up @@ -2919,8 +2919,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);

let ty = if let Some(arg_idx) = arg_idx { fn_sig.input(arg_idx) } else { fn_sig.output() };

Some(tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), ty))
Some(ty)
}

fn validate_late_bound_regions(
Expand Down
19 changes: 10 additions & 9 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
type BreakTy = Ty<'tcx>;

fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
debug!("(visit_ty) t={:?}", t);
if t == self.opaque_identity_ty {
ControlFlow::CONTINUE
} else {
Expand Down Expand Up @@ -328,14 +328,18 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(

if let ItemKind::OpaqueTy(hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
in_trait,
..
}) = item.kind
{
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
let opaque_identity_ty = if in_trait {
tcx.mk_projection(def_id.to_def_id(), substs)
} else {
tcx.mk_opaque(def_id.to_def_id(), substs)
};
let mut visitor = ProhibitOpaqueVisitor {
opaque_identity_ty: tcx.mk_opaque(
def_id.to_def_id(),
InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
),
opaque_identity_ty,
generics: tcx.generics_of(def_id),
tcx,
selftys: vec![],
Expand All @@ -344,10 +348,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
.explicit_item_bounds(def_id)
.iter()
.try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
debug!(
"check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor.opaque_identity_ty={:?}, visitor.generics={:?}",
prohibit_opaque, visitor.opaque_identity_ty, visitor.generics
);
debug!(?prohibit_opaque);

if let Some(ty) = prohibit_opaque.break_value() {
visitor.visit_item(&item);
Expand Down
Loading