Auto merge of #135272 - BoxyUwU:generic_arg_infer_reliability_2, r=compiler-errors
Forbid usage of `hir` `Infer` const/ty variants in ambiguous contexts The feature `generic_arg_infer` allows providing `_` as an argument to const generics in order to infer them. This introduces a syntactic ambiguity as to whether generic arguments are type or const arguments. In order to get around this we introduced a fourth `GenericArg` variant, `Infer` used to represent `_` as an argument to generic parameters when we don't know if its a type or a const argument. This made hir visitors that care about `TyKind::Infer` or `ConstArgKind::Infer` very error prone as checking for `TyKind::Infer`s in `visit_ty` would find *some* type infer arguments but not *all* of them as they would sometimes be lowered to `GenericArg::Infer` instead. Additionally the `visit_infer` method would previously only visit `GenericArg::Infer` not *all* infers (e.g. `TyKind::Infer`), this made it very easy to override `visit_infer` and expect it to visit all infers when in reality it would only visit *some* infers. --- This PR aims to fix those issues by making the `TyKind` and `ConstArgKind` types generic over whether the infer types/consts are represented by `Ty/ConstArgKind::Infer` or out of line (e.g. by a `GenericArg::Infer` or accessible by overiding `visit_infer`). We then make HIR Visitors convert all const args and types to the versions where infer vars are stored out of line and call `visit_infer` in cases where a `Ty`/`Const` would previously have had a `Ty/ConstArgKind::Infer` variant: API Summary ```rust enum AmbigArg {} enum Ty/ConstArgKind<Unambig = ()> { ... Infer(Unambig), } impl Ty/ConstArg { fn try_as_ambig_ty/ct(self) -> Option<Ty/ConstArg<AmbigArg>>; } impl Ty/ConstArg<AmbigArg> { fn as_unambig_ty/ct(self) -> Ty/ConstArg; } enum InferKind { Ty(Ty), Const(ConstArg), Ambig(InferArg), } trait Visitor { ... fn visit_ty/const_arg(&mut self, Ty/ConstArg<AmbigArg>) -> Self::Result; fn visit_infer(&mut self, id: HirId, sp: Span, kind: InferKind) -> Self::Result; } // blanket impl'd, not meant to be overriden trait VisitorExt { fn visit_ty/const_arg_unambig(&mut self, Ty/ConstArg) -> Self::Result; } fn walk_unambig_ty/const_arg(&mut V, Ty/ConstArg) -> Self::Result; fn walk_ty/const_arg(&mut V, Ty/ConstArg<AmbigArg>) -> Self::Result; ``` The end result is that `visit_infer` visits *all* infer args and is also the *only* way to visit an infer arg, `visit_ty` and `visit_const_arg` can now no longer encounter a `Ty/ConstArgKind::Infer`. Representing this in the type system means that it is now very difficult to mess things up, either accessing `TyKind::Infer` "just works" and you won't miss *some* type infers- or it doesn't work and you have to look at `visit_infer` or some `GenericArg::Infer` which forces you to think about the full complexity involved. Unfortunately there is no lint right now about explicitly matching on uninhabited variants, I can't find the context for why this is the case 🤷♀️ I'm not convinced the framing of un/ambig ty/consts is necessarily the right one but I'm not sure what would be better. I somewhat like calling them full/partial types based on the fact that `Ty<Partial>`/`Ty<Full>` directly specifies how many of the type kinds are actually represented compared to `Ty<Ambig>` which which leaves that to the reader to figure out based on the logical consequences of it the type being in an ambiguous position. --- tool changes have been modified in their own commits for easier reviewing by anyone getting cc'd from subtree changes. I also attempted to split out "bug fixes arising from the refactoring" into their own commit so they arent lumped in with a big general refactor commit Fixes #112110
This commit is contained in:
commit
8231e8599e
119 changed files with 1056 additions and 669 deletions
|
@ -6,9 +6,9 @@ use hir::def_id::{DefId, DefIdMap, LocalDefId};
|
|||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{GenericParamKind, ImplItemKind, intravisit};
|
||||
use rustc_hir::intravisit::VisitorExt;
|
||||
use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, intravisit};
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::util;
|
||||
|
@ -1610,7 +1610,7 @@ fn compare_synthetic_generics<'tcx>(
|
|||
struct Visitor(hir::def_id::LocalDefId);
|
||||
impl<'v> intravisit::Visitor<'v> for Visitor {
|
||||
type Result = ControlFlow<Span>;
|
||||
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) -> Self::Result {
|
||||
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) -> Self::Result {
|
||||
if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind
|
||||
&& let Res::Def(DefKind::TyParam, def_id) = path.res
|
||||
&& def_id == self.0.to_def_id()
|
||||
|
@ -1622,9 +1622,9 @@ fn compare_synthetic_generics<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
let span = input_tys.iter().find_map(|ty| {
|
||||
intravisit::Visitor::visit_ty(&mut Visitor(impl_def_id), ty).break_value()
|
||||
})?;
|
||||
let span = input_tys
|
||||
.iter()
|
||||
.find_map(|ty| Visitor(impl_def_id).visit_ty_unambig(ty).break_value())?;
|
||||
|
||||
let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds;
|
||||
let bounds = bounds.first()?.span().to(bounds.last()?.span());
|
||||
|
|
|
@ -6,10 +6,10 @@ use rustc_abi::ExternAbi;
|
|||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
|
||||
use rustc_hir::ItemKind;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{AmbigArg, ItemKind};
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
|
||||
use rustc_macros::LintDiagnostic;
|
||||
|
@ -2196,7 +2196,7 @@ impl<'tcx> Visitor<'tcx> for CollectUsageSpans<'_> {
|
|||
// Skip the generics. We only care about fields, not where clause/param bounds.
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> Self::Result {
|
||||
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
|
||||
if let hir::TyKind::Path(hir::QPath::Resolved(None, qpath)) = t.kind {
|
||||
if let Res::Def(DefKind::TyParam, def_id) = qpath.res
|
||||
&& def_id == self.param_def_id
|
||||
|
|
|
@ -28,7 +28,7 @@ use rustc_errors::{
|
|||
};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor, walk_generics};
|
||||
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt, walk_generics};
|
||||
use rustc_hir::{self as hir, GenericParamKind, HirId, Node};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
|
@ -139,29 +139,12 @@ pub(crate) struct HirPlaceholderCollector {
|
|||
}
|
||||
|
||||
impl<'v> Visitor<'v> for HirPlaceholderCollector {
|
||||
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
|
||||
if let hir::TyKind::Infer = t.kind {
|
||||
self.spans.push(t.span);
|
||||
}
|
||||
intravisit::walk_ty(self, t)
|
||||
}
|
||||
fn visit_generic_arg(&mut self, generic_arg: &'v hir::GenericArg<'v>) {
|
||||
match generic_arg {
|
||||
hir::GenericArg::Infer(inf) => {
|
||||
self.spans.push(inf.span);
|
||||
self.may_contain_const_infer = true;
|
||||
intravisit::walk_inf(self, inf);
|
||||
}
|
||||
hir::GenericArg::Type(t) => self.visit_ty(t),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
fn visit_const_arg(&mut self, const_arg: &'v hir::ConstArg<'v>) {
|
||||
if let hir::ConstArgKind::Infer(span) = const_arg.kind {
|
||||
fn visit_infer(&mut self, _inf_id: HirId, inf_span: Span, kind: InferKind<'v>) -> Self::Result {
|
||||
self.spans.push(inf_span);
|
||||
|
||||
if let InferKind::Const(_) | InferKind::Ambig(_) = kind {
|
||||
self.may_contain_const_infer = true;
|
||||
self.spans.push(span);
|
||||
}
|
||||
intravisit::walk_const_arg(self, const_arg)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -583,7 +566,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
|||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, a)| {
|
||||
if let hir::TyKind::Infer = a.kind {
|
||||
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))
|
||||
{
|
||||
|
@ -593,21 +576,21 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
|||
}
|
||||
|
||||
// Only visit the type looking for `_` if we didn't fix the type above
|
||||
visitor.visit_ty(a);
|
||||
visitor.visit_ty_unambig(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
|
||||
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);
|
||||
visitor.visit_ty_unambig(output);
|
||||
self.lower_ty(output)
|
||||
}
|
||||
}
|
||||
|
@ -1453,7 +1436,7 @@ fn recover_infer_ret_ty<'tcx>(
|
|||
});
|
||||
|
||||
let mut visitor = HirPlaceholderCollector::default();
|
||||
visitor.visit_ty(infer_ret_ty);
|
||||
visitor.visit_ty_unambig(infer_ret_ty);
|
||||
|
||||
let mut diag = bad_placeholder(icx.lowerer(), visitor.spans, "return type");
|
||||
let ret_ty = fn_sig.output();
|
||||
|
|
|
@ -3,9 +3,10 @@ use std::ops::ControlFlow;
|
|||
|
||||
use hir::intravisit::{self, Visitor};
|
||||
use hir::{GenericParamKind, HirId, Node};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::intravisit::VisitorExt;
|
||||
use rustc_hir::{self as hir, AmbigArg};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::{Span, Symbol, kw};
|
||||
|
@ -461,7 +462,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
|||
|
||||
impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
|
||||
type Result = ControlFlow<Span>;
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) -> ControlFlow<Span> {
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) -> ControlFlow<Span> {
|
||||
match ty.kind {
|
||||
hir::TyKind::BareFn(..) => {
|
||||
self.outer_index.shift_in(1);
|
||||
|
@ -539,7 +540,7 @@ impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
|
|||
if let GenericParamKind::Const { ty, default: _, synthetic: _ } = p.kind {
|
||||
let prev = self.in_param_ty;
|
||||
self.in_param_ty = true;
|
||||
let res = self.visit_ty(ty);
|
||||
let res = self.visit_ty_unambig(ty);
|
||||
self.in_param_ty = prev;
|
||||
res
|
||||
} else {
|
||||
|
|
|
@ -14,11 +14,11 @@ use rustc_ast::visit::walk_list;
|
|||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
|
||||
use rustc_hir::{
|
||||
GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap, LifetimeName, Node,
|
||||
self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap,
|
||||
LifetimeName, Node,
|
||||
};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
|
@ -489,15 +489,17 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
struct FindInferInClosureWithBinder;
|
||||
impl<'v> Visitor<'v> for FindInferInClosureWithBinder {
|
||||
type Result = ControlFlow<Span>;
|
||||
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) -> Self::Result {
|
||||
if matches!(t.kind, hir::TyKind::Infer) {
|
||||
ControlFlow::Break(t.span)
|
||||
} else {
|
||||
intravisit::walk_ty(self, t)
|
||||
}
|
||||
|
||||
fn visit_infer(
|
||||
&mut self,
|
||||
_inf_id: HirId,
|
||||
inf_span: Span,
|
||||
_kind: InferKind<'v>,
|
||||
) -> Self::Result {
|
||||
ControlFlow::Break(inf_span)
|
||||
}
|
||||
}
|
||||
FindInferInClosureWithBinder.visit_ty(ty).break_value()
|
||||
FindInferInClosureWithBinder.visit_ty_unambig(ty).break_value()
|
||||
}
|
||||
|
||||
let infer_in_rt_sp = match fn_decl.output {
|
||||
|
@ -749,7 +751,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
|
||||
match ty.kind {
|
||||
hir::TyKind::BareFn(c) => {
|
||||
let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = c
|
||||
|
@ -810,7 +812,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
intravisit::walk_ty(this, ty);
|
||||
});
|
||||
}
|
||||
hir::TyKind::TraitObject(bounds, lifetime, _) => {
|
||||
hir::TyKind::TraitObject(bounds, lifetime) => {
|
||||
let lifetime = lifetime.pointer();
|
||||
|
||||
debug!(?bounds, ?lifetime, "TraitObject");
|
||||
let scope = Scope::TraitRefBoundary { s: self.scope };
|
||||
self.with(scope, |this| {
|
||||
|
@ -827,7 +831,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
// use the object lifetime defaulting
|
||||
// rules. So e.g., `Box<dyn Debug>` becomes
|
||||
// `Box<dyn Debug + 'static>`.
|
||||
self.resolve_object_lifetime_default(lifetime)
|
||||
self.resolve_object_lifetime_default(&*lifetime)
|
||||
}
|
||||
LifetimeName::Infer => {
|
||||
// If the user writes `'_`, we use the *ordinary* elision
|
||||
|
@ -838,7 +842,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
}
|
||||
LifetimeName::Param(..) | LifetimeName::Static => {
|
||||
// If the user wrote an explicit name, use that.
|
||||
self.visit_lifetime(lifetime);
|
||||
self.visit_lifetime(&*lifetime);
|
||||
}
|
||||
LifetimeName::Error => {}
|
||||
}
|
||||
|
@ -849,7 +853,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
lifetime: self.map.defs.get(&lifetime_ref.hir_id.local_id).cloned(),
|
||||
s: self.scope,
|
||||
};
|
||||
self.with(scope, |this| this.visit_ty(mt.ty));
|
||||
self.with(scope, |this| this.visit_ty_unambig(mt.ty));
|
||||
}
|
||||
hir::TyKind::TraitAscription(bounds) => {
|
||||
let scope = Scope::TraitRefBoundary { s: self.scope };
|
||||
|
@ -891,7 +895,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
this.visit_param_bound(bound);
|
||||
}
|
||||
if let Some(ty) = ty {
|
||||
this.visit_ty(ty);
|
||||
this.visit_ty_unambig(ty);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -910,7 +914,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
}),
|
||||
Type(ty) => self.visit_early(impl_item.hir_id(), impl_item.generics, |this| {
|
||||
this.visit_generics(impl_item.generics);
|
||||
this.visit_ty(ty);
|
||||
this.visit_ty_unambig(ty);
|
||||
}),
|
||||
Const(_, _) => self.visit_early(impl_item.hir_id(), impl_item.generics, |this| {
|
||||
intravisit::walk_impl_item(this, impl_item)
|
||||
|
@ -1019,7 +1023,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
};
|
||||
self.with(scope, |this| {
|
||||
walk_list!(this, visit_generic_param, bound_generic_params);
|
||||
this.visit_ty(bounded_ty);
|
||||
this.visit_ty_unambig(bounded_ty);
|
||||
walk_list!(this, visit_param_bound, bounds);
|
||||
})
|
||||
}
|
||||
|
@ -1034,8 +1038,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
&hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
|
||||
lhs_ty, rhs_ty, ..
|
||||
}) => {
|
||||
self.visit_ty(lhs_ty);
|
||||
self.visit_ty(rhs_ty);
|
||||
self.visit_ty_unambig(lhs_ty);
|
||||
self.visit_ty_unambig(rhs_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1068,13 +1072,13 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
GenericParamKind::Lifetime { .. } => {}
|
||||
GenericParamKind::Type { default, .. } => {
|
||||
if let Some(ty) = default {
|
||||
self.visit_ty(ty);
|
||||
self.visit_ty_unambig(ty);
|
||||
}
|
||||
}
|
||||
GenericParamKind::Const { ty, default, .. } => {
|
||||
self.visit_ty(ty);
|
||||
self.visit_ty_unambig(ty);
|
||||
if let Some(default) = default {
|
||||
self.visit_const_arg(default);
|
||||
self.visit_const_arg_unambig(default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1983,15 +1987,15 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
},
|
||||
|this| {
|
||||
for input in inputs {
|
||||
this.visit_ty(input);
|
||||
this.visit_ty_unambig(input);
|
||||
}
|
||||
if !in_closure && let Some(output) = output {
|
||||
this.visit_ty(output);
|
||||
this.visit_ty_unambig(output);
|
||||
}
|
||||
},
|
||||
);
|
||||
if in_closure && let Some(output) = output {
|
||||
self.visit_ty(output);
|
||||
self.visit_ty_unambig(output);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2309,7 +2313,7 @@ fn is_late_bound_map(
|
|||
|
||||
let mut constrained_by_input = ConstrainedCollector { regions: Default::default(), tcx };
|
||||
for arg_ty in sig.decl.inputs {
|
||||
constrained_by_input.visit_ty(arg_ty);
|
||||
constrained_by_input.visit_ty_unambig(arg_ty);
|
||||
}
|
||||
|
||||
let mut appears_in_output =
|
||||
|
@ -2417,7 +2421,7 @@ fn is_late_bound_map(
|
|||
}
|
||||
|
||||
impl<'v> Visitor<'v> for ConstrainedCollector<'_> {
|
||||
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
|
||||
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
|
||||
match ty.kind {
|
||||
hir::TyKind::Path(
|
||||
hir::QPath::Resolved(Some(_), _) | hir::QPath::TypeRelative(..),
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use core::ops::ControlFlow;
|
||||
|
||||
use rustc_errors::{Applicability, StashKey, Suggestions};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::intravisit::VisitorExt;
|
||||
use rustc_hir::{self as hir, AmbigArg, HirId};
|
||||
use rustc_middle::query::plumbing::CyclePlaceholder;
|
||||
use rustc_middle::ty::fold::fold_regions;
|
||||
use rustc_middle::ty::print::with_forced_trimmed_paths;
|
||||
|
@ -451,7 +450,7 @@ fn infer_placeholder_type<'tcx>(
|
|||
let mut visitor = HirPlaceholderCollector::default();
|
||||
let node = tcx.hir_node_by_def_id(def_id);
|
||||
if let Some(ty) = node.ty() {
|
||||
visitor.visit_ty(ty);
|
||||
visitor.visit_ty_unambig(ty);
|
||||
}
|
||||
// If we have just one span, let's try to steal a const `_` feature error.
|
||||
let try_steal_span = if !tcx.features().generic_arg_infer() && visitor.spans.len() == 1
|
||||
|
@ -525,7 +524,7 @@ pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) ->
|
|||
struct HasTait;
|
||||
impl<'tcx> Visitor<'tcx> for HasTait {
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> Self::Result {
|
||||
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
|
||||
if let hir::TyKind::OpaqueDef(..) = t.kind {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
|
@ -533,5 +532,5 @@ pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) ->
|
|||
}
|
||||
}
|
||||
}
|
||||
HasTait.visit_ty(tcx.hir().expect_item(def_id).expect_ty_alias().0).is_break()
|
||||
HasTait.visit_ty_unambig(tcx.hir().expect_item(def_id).expect_ty_alias().0).is_break()
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use rustc_ast::ast::ParamKindOrd;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, struct_span_code_err};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::GenericArg;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self as hir, GenericArg};
|
||||
use rustc_middle::ty::{
|
||||
self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty,
|
||||
};
|
||||
|
@ -41,17 +40,6 @@ fn generic_arg_mismatch_err(
|
|||
param.kind.descr(),
|
||||
);
|
||||
|
||||
if let GenericParamDefKind::Const { .. } = param.kind {
|
||||
if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. })) {
|
||||
err.help("const arguments cannot yet be inferred with `_`");
|
||||
tcx.disabled_nightly_features(
|
||||
&mut err,
|
||||
param.def_id.as_local().map(|local| tcx.local_def_id_to_hir_id(local)),
|
||||
[(String::new(), sym::generic_arg_infer)],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut Diag<'_>| {
|
||||
let suggestions = vec![
|
||||
(arg.span().shrink_to_lo(), String::from("{ ")),
|
||||
|
@ -270,6 +258,21 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
|
|||
GenericParamDefKind::Const { .. },
|
||||
_,
|
||||
) => {
|
||||
if let GenericParamDefKind::Const { .. } = param.kind
|
||||
&& let GenericArg::Infer(inf) = arg
|
||||
&& !tcx.features().generic_arg_infer()
|
||||
{
|
||||
rustc_session::parse::feature_err(
|
||||
tcx.sess,
|
||||
sym::generic_arg_infer,
|
||||
inf.span,
|
||||
"const arguments cannot yet be inferred with `_`",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
// We lower to an infer even when the feature gate is not enabled
|
||||
// as it is useful for diagnostics to be able to see a `ConstKind::Infer`
|
||||
args.push(ctx.provided_kind(&args, param, arg));
|
||||
args_iter.next();
|
||||
params.next();
|
||||
|
|
|
@ -23,9 +23,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
) -> Option<ErrorGuaranteed> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
|
||||
let poly_trait_ref = if let hir::TyKind::TraitObject([poly_trait_ref, ..], tagged_ptr) =
|
||||
self_ty.kind
|
||||
else {
|
||||
&& let TraitObjectSyntax::None = tagged_ptr.tag()
|
||||
{
|
||||
poly_trait_ref
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
|
@ -294,7 +297,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let (dyn_str, paren_dyn_str) =
|
||||
if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
|
||||
|
||||
let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind {
|
||||
let sugg = if let hir::TyKind::TraitObject([_, _, ..], _) = self_ty.kind {
|
||||
// There are more than one trait bound, we need surrounding parentheses.
|
||||
vec![
|
||||
(self_ty.span.shrink_to_lo(), paren_dyn_str.to_string()),
|
||||
|
|
|
@ -517,14 +517,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
self.lowerer.lower_lifetime(lt, RegionInferReason::Param(param)).into()
|
||||
}
|
||||
(&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
|
||||
handle_ty_args(has_default, ty)
|
||||
// We handle the other parts of `Ty` in the match arm below
|
||||
handle_ty_args(has_default, ty.as_unambig_ty())
|
||||
}
|
||||
(&GenericParamDefKind::Type { has_default, .. }, GenericArg::Infer(inf)) => {
|
||||
handle_ty_args(has_default, &inf.to_ty())
|
||||
}
|
||||
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
|
||||
self.lowerer.lower_const_arg(ct, FeedConstTy::Param(param.def_id)).into()
|
||||
}
|
||||
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self
|
||||
.lowerer
|
||||
// Ambig portions of `ConstArg` are handled in the match arm below
|
||||
.lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id))
|
||||
.into(),
|
||||
(&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
|
||||
self.lowerer.ct_infer(Some(param), inf.span).into()
|
||||
}
|
||||
|
@ -2115,7 +2118,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
format!("Const::lower_const_arg: invalid qpath {qpath:?}"),
|
||||
),
|
||||
hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon),
|
||||
hir::ConstArgKind::Infer(span) => self.ct_infer(None, span),
|
||||
hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2311,7 +2314,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
tcx.late_bound_vars(hir_ty.hir_id),
|
||||
),
|
||||
),
|
||||
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
|
||||
hir::TyKind::TraitObject(bounds, tagged_ptr) => {
|
||||
let lifetime = tagged_ptr.pointer();
|
||||
let repr = tagged_ptr.tag();
|
||||
|
||||
if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) {
|
||||
// Don't continue with type analysis if the `dyn` keyword is missing
|
||||
// It generates confusing errors, especially if the user meant to use another
|
||||
|
@ -2420,7 +2426,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
Ty::new_array_with_const_len(tcx, self.lower_ty(ty), length)
|
||||
}
|
||||
hir::TyKind::Typeof(e) => tcx.type_of(e.def_id).instantiate_identity(),
|
||||
hir::TyKind::Infer => {
|
||||
hir::TyKind::Infer(()) => {
|
||||
// Infer also appears as the type of arguments or return
|
||||
// values in an ExprKind::Closure, or as
|
||||
// the type of local variables. Both of these cases are
|
||||
|
@ -2553,7 +2559,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
pub fn lower_arg_ty(&self, ty: &hir::Ty<'tcx>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
|
||||
match ty.kind {
|
||||
hir::TyKind::Infer if let Some(expected_ty) = expected_ty => {
|
||||
hir::TyKind::Infer(()) if let Some(expected_ty) = expected_ty => {
|
||||
self.record_ty(ty.hir_id, expected_ty, ty.span);
|
||||
expected_ty
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{ForeignItem, ForeignItemKind};
|
||||
use rustc_hir::intravisit::{self, Visitor, VisitorExt};
|
||||
use rustc_hir::{self as hir, AmbigArg, ForeignItem, ForeignItemKind};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::{ObligationCause, WellFormedLoc};
|
||||
use rustc_middle::bug;
|
||||
|
@ -68,11 +67,13 @@ fn diagnostic_hir_wf_check<'tcx>(
|
|||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
|
||||
let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
|
||||
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
||||
|
||||
let tcx_ty = self.icx.lower_ty(ty);
|
||||
// We don't handle infer vars but we wouldn't handle them anyway as we're creating a
|
||||
// fresh `InferCtxt` in this function.
|
||||
let tcx_ty = self.icx.lower_ty(ty.as_unambig_ty());
|
||||
// This visitor can walk into binders, resulting in the `tcx_ty` to
|
||||
// potentially reference escaping bound variables. We simply erase
|
||||
// those here.
|
||||
|
@ -149,7 +150,11 @@ fn diagnostic_hir_wf_check<'tcx>(
|
|||
.iter()
|
||||
.flat_map(|seg| seg.args().args)
|
||||
.filter_map(|arg| {
|
||||
if let hir::GenericArg::Type(ty) = arg { Some(*ty) } else { None }
|
||||
if let hir::GenericArg::Type(ty) = arg {
|
||||
Some(ty.as_unambig_ty())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.chain([impl_.self_ty])
|
||||
.collect(),
|
||||
|
@ -196,7 +201,7 @@ fn diagnostic_hir_wf_check<'tcx>(
|
|||
}
|
||||
};
|
||||
for ty in tys {
|
||||
visitor.visit_ty(ty);
|
||||
visitor.visit_ty_unambig(ty);
|
||||
}
|
||||
visitor.cause
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue