mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 16:54:01 +00:00
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:
commit
94c19c6522
@ -18,11 +18,11 @@ use rustc_ast::Recovered;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey};
|
||||
use rustc_hir as hir;
|
||||
use rustc_errors::{struct_span_code_err, Applicability, Diag, ErrorGuaranteed, StashKey, E0228};
|
||||
use rustc_hir::def::DefKind;
|
||||
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_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
@ -44,7 +44,7 @@ use std::ops::Bound;
|
||||
|
||||
use crate::check::intrinsic::intrinsic_operation_unsafety;
|
||||
use crate::errors;
|
||||
use crate::hir_ty_lowering::HirTyLowerer;
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
|
||||
pub use type_of::test_opaque_hidden_types;
|
||||
|
||||
mod generics_of;
|
||||
@ -370,16 +370,26 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn item_def_id(&self) -> DefId {
|
||||
self.item_def_id.to_def_id()
|
||||
fn item_def_id(&self) -> LocalDefId {
|
||||
self.item_def_id
|
||||
}
|
||||
|
||||
fn allow_infer(&self) -> bool {
|
||||
false
|
||||
fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
|
||||
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> {
|
||||
@ -510,6 +520,89 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
||||
fn set_tainted_by_errors(&self, err: ErrorGuaranteed) {
|
||||
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.
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::bounds::Bounds;
|
||||
use crate::collect::ItemCtxt;
|
||||
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 rustc_data_structures::fx::FxIndexSet;
|
||||
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_default_impl_trait = None;
|
||||
|
||||
// FIXME: Should ItemCtxt take a LocalDefId?
|
||||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
|
||||
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) => {
|
||||
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| {
|
||||
let (r2, span) = match bound {
|
||||
hir::GenericBound::Outlives(lt) => {
|
||||
(icx.lowerer().lower_lifetime(lt, None), lt.ident.span)
|
||||
}
|
||||
hir::GenericBound::Outlives(lt) => (
|
||||
icx.lowerer().lower_lifetime(lt, RegionInferReason::RegionPredicate),
|
||||
lt.ident.span,
|
||||
),
|
||||
bound => {
|
||||
span_bug!(
|
||||
bound.span(),
|
||||
|
@ -18,6 +18,8 @@ use crate::bounds::Bounds;
|
||||
use crate::errors;
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter};
|
||||
|
||||
use super::RegionInferReason;
|
||||
|
||||
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
/// Add a `Sized` bound to the `bounds` if appropriate.
|
||||
///
|
||||
@ -166,7 +168,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
);
|
||||
}
|
||||
hir::GenericBound::Outlives(lifetime) => {
|
||||
let region = self.lower_lifetime(lifetime, None);
|
||||
let region = self.lower_lifetime(lifetime, RegionInferReason::OutlivesBound);
|
||||
bounds.push_region_bound(
|
||||
self.tcx(),
|
||||
ty::Binder::bind_with_vars(
|
||||
|
@ -20,7 +20,6 @@ mod lint;
|
||||
mod object_safety;
|
||||
|
||||
use crate::bounds::Bounds;
|
||||
use crate::collect::HirPlaceholderCollector;
|
||||
use crate::errors::{AmbiguousLifetimeBound, WildPatTy};
|
||||
use crate::hir_ty_lowering::errors::{prohibit_assoc_item_constraint, GenericsArgsErrExtend};
|
||||
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::def::{CtorOf, DefKind, Namespace, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{walk_generics, Visitor as _};
|
||||
use rustc_hir::{GenericArg, GenericArgs, HirId};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
@ -82,6 +80,20 @@ pub enum PredicateFilter {
|
||||
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
|
||||
/// the [`rustc_middle::ty`] representation.
|
||||
///
|
||||
@ -89,15 +101,11 @@ pub enum PredicateFilter {
|
||||
pub trait HirTyLowerer<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx>;
|
||||
|
||||
/// Returns the [`DefId`] of the overarching item whose constituents get lowered.
|
||||
fn item_def_id(&self) -> DefId;
|
||||
|
||||
/// Returns `true` if the current context allows the use of inference variables.
|
||||
fn allow_infer(&self) -> bool;
|
||||
/// Returns the [`LocalDefId`] of the overarching item whose constituents get lowered.
|
||||
fn item_def_id(&self) -> LocalDefId;
|
||||
|
||||
/// Returns the region to use when a lifetime is omitted (and not elided).
|
||||
fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span)
|
||||
-> Option<ty::Region<'tcx>>;
|
||||
fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx>;
|
||||
|
||||
/// Returns the type to use when a type is omitted.
|
||||
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>,
|
||||
) -> 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.
|
||||
///
|
||||
/// Note that `ty` might be a alias type that needs normalization.
|
||||
@ -258,7 +274,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
pub fn lower_lifetime(
|
||||
&self,
|
||||
lifetime: &hir::Lifetime,
|
||||
def: Option<&ty::GenericParamDef>,
|
||||
reason: RegionInferReason<'_>,
|
||||
) -> ty::Region<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
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),
|
||||
|
||||
None => {
|
||||
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",
|
||||
)
|
||||
})
|
||||
}
|
||||
None => self.re_infer(lifetime.ident.span, reason),
|
||||
}
|
||||
}
|
||||
|
||||
@ -421,7 +423,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
def_id: DefId,
|
||||
generic_args: &'a GenericArgs<'tcx>,
|
||||
span: Span,
|
||||
inferred_params: Vec<Span>,
|
||||
infer_args: bool,
|
||||
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 {
|
||||
tcx.check_optional_stability(
|
||||
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()
|
||||
}
|
||||
};
|
||||
|
||||
match (¶m.kind, arg) {
|
||||
(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)) => {
|
||||
handle_ty_args(has_default, ty)
|
||||
@ -496,12 +492,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
.type_of(param.def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic");
|
||||
if self.lowerer.allow_infer() {
|
||||
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!(
|
||||
self.span,
|
||||
@ -524,20 +515,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
}
|
||||
}
|
||||
match param.kind {
|
||||
GenericParamDefKind::Lifetime => self
|
||||
.lowerer
|
||||
.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::Lifetime => {
|
||||
self.lowerer.re_infer(self.span, RegionInferReason::Param(param)).into()
|
||||
}
|
||||
GenericParamDefKind::Type { has_default, .. } => {
|
||||
if !infer_args && has_default {
|
||||
// No type parameter provided, but a default exists.
|
||||
@ -604,7 +584,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
def_id,
|
||||
span,
|
||||
generic_args: segment.args(),
|
||||
inferred_params: vec![],
|
||||
infer_args: segment.infer_args,
|
||||
incorrect_args: &arg_count.correct,
|
||||
};
|
||||
@ -1493,16 +1472,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
let def_id = self.item_def_id();
|
||||
debug!(item_def_id = ?def_id);
|
||||
|
||||
let parent_def_id = def_id
|
||||
.as_local()
|
||||
.map(|def_id| tcx.local_def_id_to_hir_id(def_id))
|
||||
.map(|hir_id| tcx.hir().get_parent_item(hir_id).to_def_id());
|
||||
// FIXME: document why/how this is different from `tcx.local_parent(def_id)`
|
||||
let parent_def_id =
|
||||
tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id();
|
||||
debug!(?parent_def_id);
|
||||
|
||||
// If the trait in segment is the same as the trait defining the item,
|
||||
// use the `<Self as ..>` syntax in the error.
|
||||
let is_part_of_self_trait_constraints = def_id == trait_def_id;
|
||||
let is_part_of_fn_in_self_trait = parent_def_id == Some(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 == trait_def_id;
|
||||
|
||||
let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
|
||||
vec!["Self".to_string()]
|
||||
@ -1983,7 +1961,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
}
|
||||
|
||||
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_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_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 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::Ptr(mt) => Ty::new_ptr(tcx, self.lower_ty(mt.ty), mt.mutbl),
|
||||
hir::TyKind::Ref(region, mt) => {
|
||||
let r = self.lower_lifetime(region, None);
|
||||
let r = self.lower_lifetime(region, RegionInferReason::Reference);
|
||||
debug!(?r);
|
||||
let t = self.lower_ty_common(mt.ty, true, false);
|
||||
Ty::new_ref(tcx, r, t, mt.mutbl)
|
||||
@ -2299,7 +2277,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
&lifetimes[i]
|
||||
)
|
||||
};
|
||||
self.lower_lifetime(lifetime, None).into()
|
||||
self.lower_lifetime(lifetime, RegionInferReason::Param(¶m)).into()
|
||||
} else {
|
||||
tcx.mk_param_from_def(param)
|
||||
}
|
||||
@ -2338,92 +2316,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
let bound_vars = tcx.late_bound_vars(hir_id);
|
||||
debug!(?bound_vars);
|
||||
|
||||
// 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: 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,
|
||||
};
|
||||
let (input_tys, output_ty) = self.lower_fn_sig(decl, generics, hir_id, hir_ty);
|
||||
|
||||
debug!(?output_ty);
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
// 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.
|
||||
/// If arg_idx is Some, then it corresponds to an input type index, otherwise it
|
||||
/// 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,
|
||||
fn_hir_id: HirId,
|
||||
arg_idx: Option<usize>,
|
||||
|
@ -1,5 +1,7 @@
|
||||
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_errors::{codes::*, struct_span_code_err};
|
||||
use rustc_hir as hir;
|
||||
@ -321,30 +323,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
|
||||
// Use explicitly-specified region bound.
|
||||
let region_bound = if !lifetime.is_elided() {
|
||||
self.lower_lifetime(lifetime, None)
|
||||
self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault)
|
||||
} else {
|
||||
self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
|
||||
if tcx.named_bound_var(lifetime.hir_id).is_some() {
|
||||
self.lower_lifetime(lifetime, None)
|
||||
self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault)
|
||||
} else {
|
||||
self.re_infer(None, span).unwrap_or_else(|| {
|
||||
let err = struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
self.re_infer(
|
||||
span,
|
||||
E0228,
|
||||
"the lifetime bound for this object type cannot be deduced \
|
||||
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()
|
||||
if borrowed {
|
||||
RegionInferReason::ObjectLifetimeDefault
|
||||
} else {
|
||||
err.emit()
|
||||
};
|
||||
self.set_tainted_by_errors(e);
|
||||
ty::Region::new_error(tcx, e)
|
||||
})
|
||||
RegionInferReason::BorrowedObjectLifetimeDefault
|
||||
},
|
||||
)
|
||||
}
|
||||
})
|
||||
};
|
||||
|
@ -16,7 +16,7 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{
|
||||
};
|
||||
use rustc_hir_analysis::hir_ty_lowering::{
|
||||
ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgsLowerer,
|
||||
GenericPathSegment, HirTyLowerer, IsMethodCall,
|
||||
GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason,
|
||||
};
|
||||
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
|
||||
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
|
||||
@ -1274,9 +1274,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
arg: &GenericArg<'tcx>,
|
||||
) -> ty::GenericArg<'tcx> {
|
||||
match (¶m.kind, arg) {
|
||||
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
|
||||
self.fcx.lowerer().lower_lifetime(lt, Some(param)).into()
|
||||
}
|
||||
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => self
|
||||
.fcx
|
||||
.lowerer()
|
||||
.lower_lifetime(lt, RegionInferReason::Param(param))
|
||||
.into(),
|
||||
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
|
||||
self.fcx.lower_ty(ty).raw.into()
|
||||
}
|
||||
@ -1318,9 +1320,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
) -> ty::GenericArg<'tcx> {
|
||||
let tcx = self.fcx.tcx();
|
||||
match param.kind {
|
||||
GenericParamDefKind::Lifetime => {
|
||||
self.fcx.re_infer(Some(param), self.span).unwrap().into()
|
||||
}
|
||||
GenericParamDefKind::Lifetime => self
|
||||
.fcx
|
||||
.re_infer(
|
||||
self.span,
|
||||
rustc_hir_analysis::hir_ty_lowering::RegionInferReason::Param(param),
|
||||
)
|
||||
.into(),
|
||||
GenericParamDefKind::Type { has_default, .. } => {
|
||||
if !infer_args && has_default {
|
||||
// If we have a default, then it doesn't matter that we're not
|
||||
|
@ -15,7 +15,7 @@ use hir::def_id::CRATE_DEF_ID;
|
||||
use rustc_errors::DiagCtxt;
|
||||
use rustc_hir as hir;
|
||||
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::error_reporting::sub_relations::SubRelations;
|
||||
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> {
|
||||
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
|
||||
impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn item_def_id(&self) -> DefId {
|
||||
self.body_id.to_def_id()
|
||||
fn item_def_id(&self) -> LocalDefId {
|
||||
self.body_id
|
||||
}
|
||||
|
||||
fn allow_infer(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
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),
|
||||
fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
|
||||
let v = match reason {
|
||||
RegionInferReason::Param(def) => infer::RegionParameterDefinition(span, def.name),
|
||||
_ => 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> {
|
||||
@ -350,6 +346,22 @@ impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> {
|
||||
fn set_tainted_by_errors(&self, e: ErrorGuaranteed) {
|
||||
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
|
||||
|
@ -7,7 +7,9 @@ use rustc_hir::GenericArg;
|
||||
use rustc_hir_analysis::hir_ty_lowering::generics::{
|
||||
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_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
|
||||
@ -388,9 +390,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
||||
arg: &GenericArg<'tcx>,
|
||||
) -> ty::GenericArg<'tcx> {
|
||||
match (¶m.kind, arg) {
|
||||
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
|
||||
self.cfcx.fcx.lowerer().lower_lifetime(lt, Some(param)).into()
|
||||
}
|
||||
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => self
|
||||
.cfcx
|
||||
.fcx
|
||||
.lowerer()
|
||||
.lower_lifetime(lt, RegionInferReason::Param(param))
|
||||
.into(),
|
||||
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
|
||||
self.cfcx.lower_ty(ty).raw.into()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user