Rollup merge of #125819 - oli-obk:localize, r=fmease

Various `HirTyLowerer` cleanups

Previously there was some ad-hoc specialization going on, because you could call `allows_infer`, which basically was deciding between whether the trait object was backed by `FnCtxt` or by `ItemCtxt`. I moved all the different logic into dedicated methods on `HirTyLowerer` and removed `allows_infer`

best reviewed commit-by-commit
This commit is contained in:
Matthias Krüger
2024-06-05 18:21:10 +02:00
committed by GitHub
8 changed files with 221 additions and 210 deletions

View File

@@ -18,11 +18,11 @@ use rustc_ast::Recovered;
use rustc_data_structures::captures::Captures; use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_data_structures::unord::UnordMap; use rustc_data_structures::unord::UnordMap;
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey}; use rustc_errors::{struct_span_code_err, Applicability, Diag, ErrorGuaranteed, StashKey, E0228};
use rustc_hir as hir;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, walk_generics, Visitor};
use rustc_hir::{self as hir};
use rustc_hir::{GenericParamKind, Node}; use rustc_hir::{GenericParamKind, Node};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause; use rustc_infer::traits::ObligationCause;
@@ -44,7 +44,7 @@ use std::ops::Bound;
use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::check::intrinsic::intrinsic_operation_unsafety;
use crate::errors; use crate::errors;
use crate::hir_ty_lowering::HirTyLowerer; use crate::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
pub use type_of::test_opaque_hidden_types; pub use type_of::test_opaque_hidden_types;
mod generics_of; mod generics_of;
@@ -370,16 +370,26 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
self.tcx self.tcx
} }
fn item_def_id(&self) -> DefId { fn item_def_id(&self) -> LocalDefId {
self.item_def_id.to_def_id() self.item_def_id
} }
fn allow_infer(&self) -> bool { fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
false if let RegionInferReason::BorrowedObjectLifetimeDefault = reason {
let e = struct_span_code_err!(
self.tcx().dcx(),
span,
E0228,
"the lifetime bound for this object type cannot be deduced \
from context; please supply an explicit bound"
)
.emit();
self.set_tainted_by_errors(e);
ty::Region::new_error(self.tcx(), e)
} else {
// This indicates an illegal lifetime in a non-assoc-trait position
ty::Region::new_error_with_message(self.tcx(), span, "unelided lifetime in signature")
} }
fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option<ty::Region<'tcx>> {
None
} }
fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
@@ -510,6 +520,89 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
fn set_tainted_by_errors(&self, err: ErrorGuaranteed) { fn set_tainted_by_errors(&self, err: ErrorGuaranteed) {
self.tainted_by_errors.set(Some(err)); self.tainted_by_errors.set(Some(err));
} }
fn lower_fn_sig(
&self,
decl: &hir::FnDecl<'tcx>,
generics: Option<&hir::Generics<'_>>,
hir_id: rustc_hir::HirId,
hir_ty: Option<&hir::Ty<'_>>,
) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
let tcx = self.tcx();
// We proactively collect all the inferred type params to emit a single error per fn def.
let mut visitor = HirPlaceholderCollector::default();
let mut infer_replacements = vec![];
if let Some(generics) = generics {
walk_generics(&mut visitor, generics);
}
let input_tys = decl
.inputs
.iter()
.enumerate()
.map(|(i, a)| {
if let hir::TyKind::Infer = a.kind {
if let Some(suggested_ty) =
self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
{
infer_replacements.push((a.span, suggested_ty.to_string()));
return Ty::new_error_with_message(tcx, a.span, suggested_ty.to_string());
}
}
// Only visit the type looking for `_` if we didn't fix the type above
visitor.visit_ty(a);
self.lowerer().lower_arg_ty(a, None)
})
.collect();
let output_ty = match decl.output {
hir::FnRetTy::Return(output) => {
if let hir::TyKind::Infer = output.kind
&& let Some(suggested_ty) =
self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
{
infer_replacements.push((output.span, suggested_ty.to_string()));
Ty::new_error_with_message(tcx, output.span, suggested_ty.to_string())
} else {
visitor.visit_ty(output);
self.lower_ty(output)
}
}
hir::FnRetTy::DefaultReturn(..) => tcx.types.unit,
};
if !(visitor.0.is_empty() && infer_replacements.is_empty()) {
// We check for the presence of
// `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
let mut diag = crate::collect::placeholder_type_error_diag(
tcx,
generics,
visitor.0,
infer_replacements.iter().map(|(s, _)| *s).collect(),
true,
hir_ty,
"function",
);
if !infer_replacements.is_empty() {
diag.multipart_suggestion(
format!(
"try replacing `_` with the type{} in the corresponding trait method signature",
rustc_errors::pluralize!(infer_replacements.len()),
),
infer_replacements,
Applicability::MachineApplicable,
);
}
self.set_tainted_by_errors(diag.emit());
}
(input_tys, output_ty)
}
} }
/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present. /// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.

View File

@@ -1,7 +1,7 @@
use crate::bounds::Bounds; use crate::bounds::Bounds;
use crate::collect::ItemCtxt; use crate::collect::ItemCtxt;
use crate::constrained_generic_params as cgp; use crate::constrained_generic_params as cgp;
use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter}; use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason};
use hir::{HirId, Node}; use hir::{HirId, Node};
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir; use rustc_hir as hir;
@@ -117,7 +117,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
let mut is_trait = None; let mut is_trait = None;
let mut is_default_impl_trait = None; let mut is_default_impl_trait = None;
// FIXME: Should ItemCtxt take a LocalDefId?
let icx = ItemCtxt::new(tcx, def_id); let icx = ItemCtxt::new(tcx, def_id);
const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty(); const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
@@ -244,12 +243,15 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
} }
hir::WherePredicate::RegionPredicate(region_pred) => { hir::WherePredicate::RegionPredicate(region_pred) => {
let r1 = icx.lowerer().lower_lifetime(region_pred.lifetime, None); let r1 = icx
.lowerer()
.lower_lifetime(region_pred.lifetime, RegionInferReason::RegionPredicate);
predicates.extend(region_pred.bounds.iter().map(|bound| { predicates.extend(region_pred.bounds.iter().map(|bound| {
let (r2, span) = match bound { let (r2, span) = match bound {
hir::GenericBound::Outlives(lt) => { hir::GenericBound::Outlives(lt) => (
(icx.lowerer().lower_lifetime(lt, None), lt.ident.span) icx.lowerer().lower_lifetime(lt, RegionInferReason::RegionPredicate),
} lt.ident.span,
),
bound => { bound => {
span_bug!( span_bug!(
bound.span(), bound.span(),

View File

@@ -18,6 +18,8 @@ use crate::bounds::Bounds;
use crate::errors; use crate::errors;
use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter}; use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter};
use super::RegionInferReason;
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// Add a `Sized` bound to the `bounds` if appropriate. /// Add a `Sized` bound to the `bounds` if appropriate.
/// ///
@@ -166,7 +168,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
); );
} }
hir::GenericBound::Outlives(lifetime) => { hir::GenericBound::Outlives(lifetime) => {
let region = self.lower_lifetime(lifetime, None); let region = self.lower_lifetime(lifetime, RegionInferReason::OutlivesBound);
bounds.push_region_bound( bounds.push_region_bound(
self.tcx(), self.tcx(),
ty::Binder::bind_with_vars( ty::Binder::bind_with_vars(

View File

@@ -20,7 +20,6 @@ mod lint;
mod object_safety; mod object_safety;
use crate::bounds::Bounds; use crate::bounds::Bounds;
use crate::collect::HirPlaceholderCollector;
use crate::errors::{AmbiguousLifetimeBound, WildPatTy}; use crate::errors::{AmbiguousLifetimeBound, WildPatTy};
use crate::hir_ty_lowering::errors::{prohibit_assoc_item_constraint, GenericsArgsErrExtend}; use crate::hir_ty_lowering::errors::{prohibit_assoc_item_constraint, GenericsArgsErrExtend};
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
@@ -34,7 +33,6 @@ use rustc_errors::{
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{walk_generics, Visitor as _};
use rustc_hir::{GenericArg, GenericArgs, HirId}; use rustc_hir::{GenericArg, GenericArgs, HirId};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause; use rustc_infer::traits::ObligationCause;
@@ -82,6 +80,20 @@ pub enum PredicateFilter {
SelfAndAssociatedTypeBounds, SelfAndAssociatedTypeBounds,
} }
#[derive(Debug)]
pub enum RegionInferReason<'a> {
/// Lifetime on a trait object behind a reference.
/// This allows inferring information from the reference.
BorrowedObjectLifetimeDefault,
/// A trait object's lifetime.
ObjectLifetimeDefault,
/// Generic lifetime parameter
Param(&'a ty::GenericParamDef),
RegionPredicate,
Reference,
OutlivesBound,
}
/// A context which can lower type-system entities from the [HIR][hir] to /// A context which can lower type-system entities from the [HIR][hir] to
/// the [`rustc_middle::ty`] representation. /// the [`rustc_middle::ty`] representation.
/// ///
@@ -89,15 +101,11 @@ pub enum PredicateFilter {
pub trait HirTyLowerer<'tcx> { pub trait HirTyLowerer<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx>; fn tcx(&self) -> TyCtxt<'tcx>;
/// Returns the [`DefId`] of the overarching item whose constituents get lowered. /// Returns the [`LocalDefId`] of the overarching item whose constituents get lowered.
fn item_def_id(&self) -> DefId; fn item_def_id(&self) -> LocalDefId;
/// Returns `true` if the current context allows the use of inference variables.
fn allow_infer(&self) -> bool;
/// Returns the region to use when a lifetime is omitted (and not elided). /// Returns the region to use when a lifetime is omitted (and not elided).
fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx>;
-> Option<ty::Region<'tcx>>;
/// Returns the type to use when a type is omitted. /// Returns the type to use when a type is omitted.
fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>; fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>;
@@ -151,6 +159,14 @@ pub trait HirTyLowerer<'tcx> {
poly_trait_ref: ty::PolyTraitRef<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Ty<'tcx>; ) -> Ty<'tcx>;
fn lower_fn_sig(
&self,
decl: &hir::FnDecl<'tcx>,
generics: Option<&hir::Generics<'_>>,
hir_id: HirId,
hir_ty: Option<&hir::Ty<'_>>,
) -> (Vec<Ty<'tcx>>, Ty<'tcx>);
/// Returns `AdtDef` if `ty` is an ADT. /// Returns `AdtDef` if `ty` is an ADT.
/// ///
/// Note that `ty` might be a alias type that needs normalization. /// Note that `ty` might be a alias type that needs normalization.
@@ -258,7 +274,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
pub fn lower_lifetime( pub fn lower_lifetime(
&self, &self,
lifetime: &hir::Lifetime, lifetime: &hir::Lifetime,
def: Option<&ty::GenericParamDef>, reason: RegionInferReason<'_>,
) -> ty::Region<'tcx> { ) -> ty::Region<'tcx> {
let tcx = self.tcx(); let tcx = self.tcx();
let lifetime_name = |def_id| tcx.hir().name(tcx.local_def_id_to_hir_id(def_id)); let lifetime_name = |def_id| tcx.hir().name(tcx.local_def_id_to_hir_id(def_id));
@@ -292,21 +308,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
Some(rbv::ResolvedArg::Error(guar)) => ty::Region::new_error(tcx, guar), Some(rbv::ResolvedArg::Error(guar)) => ty::Region::new_error(tcx, guar),
None => { None => self.re_infer(lifetime.ident.span, reason),
self.re_infer(def, lifetime.ident.span).unwrap_or_else(|| {
debug!(?lifetime, "unelided lifetime in signature");
// This indicates an illegal lifetime
// elision. `resolve_lifetime` should have
// reported an error in this case -- but if
// not, let's error out.
ty::Region::new_error_with_message(
tcx,
lifetime.ident.span,
"unelided lifetime in signature",
)
})
}
} }
} }
@@ -421,7 +423,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
def_id: DefId, def_id: DefId,
generic_args: &'a GenericArgs<'tcx>, generic_args: &'a GenericArgs<'tcx>,
span: Span, span: Span,
inferred_params: Vec<Span>,
infer_args: bool, infer_args: bool,
incorrect_args: &'a Result<(), GenericArgCountMismatch>, incorrect_args: &'a Result<(), GenericArgCountMismatch>,
} }
@@ -450,7 +451,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
} }
} }
let mut handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| { let handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| {
if has_default { if has_default {
tcx.check_optional_stability( tcx.check_optional_stability(
param.def_id, param.def_id,
@@ -467,17 +468,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}, },
); );
} }
if let (hir::TyKind::Infer, false) = (&ty.kind, self.lowerer.allow_infer()) {
self.inferred_params.push(ty.span);
Ty::new_misc_error(tcx).into()
} else {
self.lowerer.lower_ty(ty).into() self.lowerer.lower_ty(ty).into()
}
}; };
match (&param.kind, arg) { match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
self.lowerer.lower_lifetime(lt, Some(param)).into() self.lowerer.lower_lifetime(lt, RegionInferReason::Param(param)).into()
} }
(&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
handle_ty_args(has_default, ty) handle_ty_args(has_default, ty)
@@ -496,12 +492,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.type_of(param.def_id) .type_of(param.def_id)
.no_bound_vars() .no_bound_vars()
.expect("const parameter types cannot be generic"); .expect("const parameter types cannot be generic");
if self.lowerer.allow_infer() {
self.lowerer.ct_infer(ty, Some(param), inf.span).into() self.lowerer.ct_infer(ty, Some(param), inf.span).into()
} else {
self.inferred_params.push(inf.span);
ty::Const::new_misc_error(tcx, ty).into()
}
} }
(kind, arg) => span_bug!( (kind, arg) => span_bug!(
self.span, self.span,
@@ -524,20 +515,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
} }
} }
match param.kind { match param.kind {
GenericParamDefKind::Lifetime => self GenericParamDefKind::Lifetime => {
.lowerer self.lowerer.re_infer(self.span, RegionInferReason::Param(param)).into()
.re_infer(Some(param), self.span) }
.unwrap_or_else(|| {
debug!(?param, "unelided lifetime in signature");
// This indicates an illegal lifetime in a non-assoc-trait position
ty::Region::new_error_with_message(
tcx,
self.span,
"unelided lifetime in signature",
)
})
.into(),
GenericParamDefKind::Type { has_default, .. } => { GenericParamDefKind::Type { has_default, .. } => {
if !infer_args && has_default { if !infer_args && has_default {
// No type parameter provided, but a default exists. // No type parameter provided, but a default exists.
@@ -604,7 +584,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
def_id, def_id,
span, span,
generic_args: segment.args(), generic_args: segment.args(),
inferred_params: vec![],
infer_args: segment.infer_args, infer_args: segment.infer_args,
incorrect_args: &arg_count.correct, incorrect_args: &arg_count.correct,
}; };
@@ -1493,16 +1472,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let def_id = self.item_def_id(); let def_id = self.item_def_id();
debug!(item_def_id = ?def_id); debug!(item_def_id = ?def_id);
let parent_def_id = def_id // FIXME: document why/how this is different from `tcx.local_parent(def_id)`
.as_local() let parent_def_id =
.map(|def_id| tcx.local_def_id_to_hir_id(def_id)) tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id();
.map(|hir_id| tcx.hir().get_parent_item(hir_id).to_def_id());
debug!(?parent_def_id); debug!(?parent_def_id);
// If the trait in segment is the same as the trait defining the item, // If the trait in segment is the same as the trait defining the item,
// use the `<Self as ..>` syntax in the error. // use the `<Self as ..>` syntax in the error.
let is_part_of_self_trait_constraints = def_id == trait_def_id; let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id;
let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id); let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id;
let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
vec!["Self".to_string()] vec!["Self".to_string()]
@@ -1983,7 +1961,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
} }
let sig_generics = self.tcx().generics_of(sig_id); let sig_generics = self.tcx().generics_of(sig_id);
let parent = self.tcx().parent(self.item_def_id()); let parent = self.tcx().local_parent(self.item_def_id());
let parent_generics = self.tcx().generics_of(parent); let parent_generics = self.tcx().generics_of(parent);
let parent_is_trait = (self.tcx().def_kind(parent) == DefKind::Trait) as usize; let parent_is_trait = (self.tcx().def_kind(parent) == DefKind::Trait) as usize;
@@ -2022,7 +2000,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let sig = self.tcx().fn_sig(sig_id); let sig = self.tcx().fn_sig(sig_id);
let sig_generics = self.tcx().generics_of(sig_id); let sig_generics = self.tcx().generics_of(sig_id);
let parent = self.tcx().parent(self.item_def_id()); let parent = self.tcx().local_parent(self.item_def_id());
let parent_def_kind = self.tcx().def_kind(parent); let parent_def_kind = self.tcx().def_kind(parent);
let sig = if let DefKind::Impl { .. } = parent_def_kind let sig = if let DefKind::Impl { .. } = parent_def_kind
@@ -2070,7 +2048,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.lower_ty(ty)), hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.lower_ty(ty)),
hir::TyKind::Ptr(mt) => Ty::new_ptr(tcx, self.lower_ty(mt.ty), mt.mutbl), hir::TyKind::Ptr(mt) => Ty::new_ptr(tcx, self.lower_ty(mt.ty), mt.mutbl),
hir::TyKind::Ref(region, mt) => { hir::TyKind::Ref(region, mt) => {
let r = self.lower_lifetime(region, None); let r = self.lower_lifetime(region, RegionInferReason::Reference);
debug!(?r); debug!(?r);
let t = self.lower_ty_common(mt.ty, true, false); let t = self.lower_ty_common(mt.ty, true, false);
Ty::new_ref(tcx, r, t, mt.mutbl) Ty::new_ref(tcx, r, t, mt.mutbl)
@@ -2299,7 +2277,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&lifetimes[i] &lifetimes[i]
) )
}; };
self.lower_lifetime(lifetime, None).into() self.lower_lifetime(lifetime, RegionInferReason::Param(&param)).into()
} else { } else {
tcx.mk_param_from_def(param) tcx.mk_param_from_def(param)
} }
@@ -2338,92 +2316,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let bound_vars = tcx.late_bound_vars(hir_id); let bound_vars = tcx.late_bound_vars(hir_id);
debug!(?bound_vars); debug!(?bound_vars);
// We proactively collect all the inferred type params to emit a single error per fn def. let (input_tys, output_ty) = self.lower_fn_sig(decl, generics, hir_id, hir_ty);
let mut visitor = HirPlaceholderCollector::default();
let mut infer_replacements = vec![];
if let Some(generics) = generics {
walk_generics(&mut visitor, generics);
}
let input_tys: Vec<_> = decl
.inputs
.iter()
.enumerate()
.map(|(i, a)| {
if let hir::TyKind::Infer = a.kind
&& !self.allow_infer()
{
if let Some(suggested_ty) =
self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
{
infer_replacements.push((a.span, suggested_ty.to_string()));
return Ty::new_error_with_message(
self.tcx(),
a.span,
suggested_ty.to_string(),
);
}
}
// Only visit the type looking for `_` if we didn't fix the type above
visitor.visit_ty(a);
self.lower_arg_ty(a, None)
})
.collect();
let output_ty = match decl.output {
hir::FnRetTy::Return(output) => {
if let hir::TyKind::Infer = output.kind
&& !self.allow_infer()
&& let Some(suggested_ty) =
self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
{
infer_replacements.push((output.span, suggested_ty.to_string()));
Ty::new_error_with_message(self.tcx(), output.span, suggested_ty.to_string())
} else {
visitor.visit_ty(output);
self.lower_ty(output)
}
}
hir::FnRetTy::DefaultReturn(..) => tcx.types.unit,
};
debug!(?output_ty); debug!(?output_ty);
let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi); let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi);
let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars); let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
if !self.allow_infer() && !(visitor.0.is_empty() && infer_replacements.is_empty()) {
// We always collect the spans for placeholder types when evaluating `fn`s, but we
// only want to emit an error complaining about them if infer types (`_`) are not
// allowed. `allow_infer` gates this behavior. We check for the presence of
// `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
let mut diag = crate::collect::placeholder_type_error_diag(
tcx,
generics,
visitor.0,
infer_replacements.iter().map(|(s, _)| *s).collect(),
true,
hir_ty,
"function",
);
if !infer_replacements.is_empty() {
diag.multipart_suggestion(
format!(
"try replacing `_` with the type{} in the corresponding trait method signature",
rustc_errors::pluralize!(infer_replacements.len()),
),
infer_replacements,
Applicability::MachineApplicable,
);
}
self.set_tainted_by_errors(diag.emit());
}
// Find any late-bound regions declared in return type that do // Find any late-bound regions declared in return type that do
// not appear in the arguments. These are not well-formed. // not appear in the arguments. These are not well-formed.
// //
@@ -2453,7 +2352,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// corresponding function in the trait that the impl implements, if it exists. /// corresponding function in the trait that the impl implements, if it exists.
/// If arg_idx is Some, then it corresponds to an input type index, otherwise it /// If arg_idx is Some, then it corresponds to an input type index, otherwise it
/// corresponds to the return type. /// corresponds to the return type.
fn suggest_trait_fn_ty_for_impl_fn_infer( pub(super) fn suggest_trait_fn_ty_for_impl_fn_infer(
&self, &self,
fn_hir_id: HirId, fn_hir_id: HirId,
arg_idx: Option<usize>, arg_idx: Option<usize>,

View File

@@ -1,5 +1,7 @@
use crate::bounds::Bounds; use crate::bounds::Bounds;
use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds}; use crate::hir_ty_lowering::{
GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds, RegionInferReason,
};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::{codes::*, struct_span_code_err}; use rustc_errors::{codes::*, struct_span_code_err};
use rustc_hir as hir; use rustc_hir as hir;
@@ -321,30 +323,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// Use explicitly-specified region bound. // Use explicitly-specified region bound.
let region_bound = if !lifetime.is_elided() { let region_bound = if !lifetime.is_elided() {
self.lower_lifetime(lifetime, None) self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault)
} else { } else {
self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
if tcx.named_bound_var(lifetime.hir_id).is_some() { if tcx.named_bound_var(lifetime.hir_id).is_some() {
self.lower_lifetime(lifetime, None) self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault)
} else { } else {
self.re_infer(None, span).unwrap_or_else(|| { self.re_infer(
let err = struct_span_code_err!(
tcx.dcx(),
span, span,
E0228, if borrowed {
"the lifetime bound for this object type cannot be deduced \ RegionInferReason::ObjectLifetimeDefault
from context; please supply an explicit bound"
);
let e = if borrowed {
// We will have already emitted an error E0106 complaining about a
// missing named lifetime in `&dyn Trait`, so we elide this one.
err.delay_as_bug()
} else { } else {
err.emit() RegionInferReason::BorrowedObjectLifetimeDefault
}; },
self.set_tainted_by_errors(e); )
ty::Region::new_error(tcx, e)
})
} }
}) })
}; };

View File

@@ -16,7 +16,7 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{
}; };
use rustc_hir_analysis::hir_ty_lowering::{ use rustc_hir_analysis::hir_ty_lowering::{
ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgsLowerer, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgsLowerer,
GenericPathSegment, HirTyLowerer, IsMethodCall, GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason,
}; };
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
@@ -1274,9 +1274,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
arg: &GenericArg<'tcx>, arg: &GenericArg<'tcx>,
) -> ty::GenericArg<'tcx> { ) -> ty::GenericArg<'tcx> {
match (&param.kind, arg) { match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => self
self.fcx.lowerer().lower_lifetime(lt, Some(param)).into() .fcx
} .lowerer()
.lower_lifetime(lt, RegionInferReason::Param(param))
.into(),
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
self.fcx.lower_ty(ty).raw.into() self.fcx.lower_ty(ty).raw.into()
} }
@@ -1318,9 +1320,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> ty::GenericArg<'tcx> { ) -> ty::GenericArg<'tcx> {
let tcx = self.fcx.tcx(); let tcx = self.fcx.tcx();
match param.kind { match param.kind {
GenericParamDefKind::Lifetime => { GenericParamDefKind::Lifetime => self
self.fcx.re_infer(Some(param), self.span).unwrap().into() .fcx
} .re_infer(
self.span,
rustc_hir_analysis::hir_ty_lowering::RegionInferReason::Param(param),
)
.into(),
GenericParamDefKind::Type { has_default, .. } => { GenericParamDefKind::Type { has_default, .. } => {
if !infer_args && has_default { if !infer_args && has_default {
// If we have a default, then it doesn't matter that we're not // If we have a default, then it doesn't matter that we're not

View File

@@ -15,7 +15,7 @@ use hir::def_id::CRATE_DEF_ID;
use rustc_errors::DiagCtxt; use rustc_errors::DiagCtxt;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
use rustc_infer::infer; use rustc_infer::infer;
use rustc_infer::infer::error_reporting::sub_relations::SubRelations; use rustc_infer::infer::error_reporting::sub_relations::SubRelations;
use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::error_reporting::TypeErrCtxt;
@@ -213,25 +213,21 @@ impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
} }
} }
impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> { impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx self.tcx
} }
fn item_def_id(&self) -> DefId { fn item_def_id(&self) -> LocalDefId {
self.body_id.to_def_id() self.body_id
} }
fn allow_infer(&self) -> bool { fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
true let v = match reason {
} RegionInferReason::Param(def) => infer::RegionParameterDefinition(span, def.name),
_ => infer::MiscVariable(span),
fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> {
let v = match def {
Some(def) => infer::RegionParameterDefinition(span, def.name),
None => infer::MiscVariable(span),
}; };
Some(self.next_region_var(v)) self.next_region_var(v)
} }
fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
@@ -350,6 +346,22 @@ impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> {
fn set_tainted_by_errors(&self, e: ErrorGuaranteed) { fn set_tainted_by_errors(&self, e: ErrorGuaranteed) {
self.infcx.set_tainted_by_errors(e) self.infcx.set_tainted_by_errors(e)
} }
fn lower_fn_sig(
&self,
decl: &rustc_hir::FnDecl<'tcx>,
_generics: Option<&rustc_hir::Generics<'_>>,
_hir_id: rustc_hir::HirId,
_hir_ty: Option<&hir::Ty<'_>>,
) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_arg_ty(a, None)).collect();
let output_ty = match decl.output {
hir::FnRetTy::Return(output) => self.lowerer().lower_ty(output),
hir::FnRetTy::DefaultReturn(..) => self.tcx().types.unit,
};
(input_tys, output_ty)
}
} }
/// The `ty` representation of a user-provided type. Depending on the use-site /// The `ty` representation of a user-provided type. Depending on the use-site

View File

@@ -7,7 +7,9 @@ use rustc_hir::GenericArg;
use rustc_hir_analysis::hir_ty_lowering::generics::{ use rustc_hir_analysis::hir_ty_lowering::generics::{
check_generic_arg_count_for_call, lower_generic_args, check_generic_arg_count_for_call, lower_generic_args,
}; };
use rustc_hir_analysis::hir_ty_lowering::{GenericArgsLowerer, HirTyLowerer, IsMethodCall}; use rustc_hir_analysis::hir_ty_lowering::{
GenericArgsLowerer, HirTyLowerer, IsMethodCall, RegionInferReason,
};
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk}; use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk};
use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
@@ -388,9 +390,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
arg: &GenericArg<'tcx>, arg: &GenericArg<'tcx>,
) -> ty::GenericArg<'tcx> { ) -> ty::GenericArg<'tcx> {
match (&param.kind, arg) { match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => self
self.cfcx.fcx.lowerer().lower_lifetime(lt, Some(param)).into() .cfcx
} .fcx
.lowerer()
.lower_lifetime(lt, RegionInferReason::Param(param))
.into(),
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
self.cfcx.lower_ty(ty).raw.into() self.cfcx.lower_ty(ty).raw.into()
} }