diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f851725058d4b..8cab83707dcbc 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -336,6 +336,9 @@ pub enum ParamKindOrd { // is active. Specifically, if it's only `min_const_generics`, it will still require // ordering consts after types. Const { unordered: bool }, + // `Infer` is not actually constructed directly from the AST, but is implicitly constructed + // during HIR lowering, and `ParamKindOrd` will implicitly order inferred variables last. + Infer, } impl Ord for ParamKindOrd { @@ -343,7 +346,7 @@ impl Ord for ParamKindOrd { use ParamKindOrd::*; let to_int = |v| match v { Lifetime => 0, - Type | Const { unordered: true } => 1, + Infer | Type | Const { unordered: true } => 1, // technically both consts should be ordered equally, // but only one is ever encountered at a time, so this is // fine. @@ -371,6 +374,7 @@ impl fmt::Display for ParamKindOrd { ParamKindOrd::Lifetime => "lifetime".fmt(f), ParamKindOrd::Type => "type".fmt(f), ParamKindOrd::Const { .. } => "const".fmt(f), + ParamKindOrd::Infer => "infer".fmt(f), } } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 57bf7be40566e..3bd42ba6090dd 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -51,7 +51,7 @@ use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{DefId, DefIdMap, DefPathHash, LocalDefId, CRATE_DEF_ID}; use rustc_hir::definitions::{DefKey, DefPathData, Definitions}; use rustc_hir::intravisit; -use rustc_hir::{ConstArg, GenericArg, ParamName}; +use rustc_hir::{ConstArg, GenericArg, InferKind, ParamName}; use rustc_index::vec::{Idx, IndexVec}; use rustc_session::lint::builtin::{BARE_TRAIT_OBJECTS, MISSING_ABI}; use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; @@ -1243,48 +1243,59 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match arg { ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(<)), ast::GenericArg::Type(ty) => { - // We parse const arguments as path types as we cannot distinguish them during - // parsing. We try to resolve that ambiguity by attempting resolution in both the - // type and value namespaces. If we resolved the path in the value namespace, we - // transform it into a generic const argument. - if let TyKind::Path(ref qself, ref path) = ty.kind { - if let Some(partial_res) = self.resolver.get_partial_res(ty.id) { - let res = partial_res.base_res(); - if !res.matches_ns(Namespace::TypeNS) { - debug!( - "lower_generic_arg: Lowering type argument as const argument: {:?}", - ty, - ); - - // Construct a AnonConst where the expr is the "ty"'s path. - - let parent_def_id = self.current_hir_id_owner.0; - let node_id = self.resolver.next_node_id(); - - // Add a definition for the in-band const def. - self.resolver.create_def( - parent_def_id, - node_id, - DefPathData::AnonConst, - ExpnId::root(), - ty.span, - ); - - let path_expr = Expr { - id: ty.id, - kind: ExprKind::Path(qself.clone(), path.clone()), - span: ty.span, - attrs: AttrVec::new(), - tokens: None, - }; - - let ct = self.with_new_scopes(|this| hir::AnonConst { - hir_id: this.lower_node_id(node_id), - body: this.lower_const_body(path_expr.span, Some(&path_expr)), - }); - return GenericArg::Const(ConstArg { value: ct, span: ty.span }); + match ty.kind { + TyKind::Infer if self.sess.features_untracked().generic_arg_infer => { + let hir_id = self.lower_node_id(ty.id); + return GenericArg::Infer(hir::InferArg { + hir_id, + span: ty.span, + kind: InferKind::Type, + }); + } + // We parse const arguments as path types as we cannot distinguish them during + // parsing. We try to resolve that ambiguity by attempting resolution in both the + // type and value namespaces. If we resolved the path in the value namespace, we + // transform it into a generic const argument. + TyKind::Path(ref qself, ref path) => { + if let Some(partial_res) = self.resolver.get_partial_res(ty.id) { + let res = partial_res.base_res(); + if !res.matches_ns(Namespace::TypeNS) { + debug!( + "lower_generic_arg: Lowering type argument as const argument: {:?}", + ty, + ); + + // Construct a AnonConst where the expr is the "ty"'s path. + + let parent_def_id = self.current_hir_id_owner.0; + let node_id = self.resolver.next_node_id(); + + // Add a definition for the in-band const def. + self.resolver.create_def( + parent_def_id, + node_id, + DefPathData::AnonConst, + ExpnId::root(), + ty.span, + ); + + let path_expr = Expr { + id: ty.id, + kind: ExprKind::Path(qself.clone(), path.clone()), + span: ty.span, + attrs: AttrVec::new(), + tokens: None, + }; + + let ct = self.with_new_scopes(|this| hir::AnonConst { + hir_id: this.lower_node_id(node_id), + body: this.lower_const_body(path_expr.span, Some(&path_expr)), + }); + return GenericArg::Const(ConstArg { value: ct, span: ty.span }); + } } } + _ => {} } GenericArg::Type(self.lower_ty_direct(&ty, itctx)) } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 952fe3f9f8188..803e4a2e59def 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -680,6 +680,9 @@ declare_features! ( /// Allows `cfg(target_abi = "...")`. (active, cfg_target_abi, "1.55.0", Some(80970), None), + /// Infer generic args for both consts and types. + (active, generic_arg_infer, "1.55.0", Some(85077), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 389d1e5899f70..db7fe6cb12ff1 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -254,11 +254,38 @@ pub struct ConstArg { pub span: Span, } +#[derive(Copy, Clone, Encodable, Debug, HashStable_Generic)] +pub enum InferKind { + Const, + Type, +} + +impl InferKind { + #[inline] + pub fn is_type(self) -> bool { + matches!(self, InferKind::Type) + } +} + +#[derive(Encodable, Debug, HashStable_Generic)] +pub struct InferArg { + pub hir_id: HirId, + pub kind: InferKind, + pub span: Span, +} + +impl InferArg { + pub fn to_ty(&self) -> Ty<'_> { + Ty { kind: TyKind::Infer, span: self.span, hir_id: self.hir_id } + } +} + #[derive(Debug, HashStable_Generic)] pub enum GenericArg<'hir> { Lifetime(Lifetime), Type(Ty<'hir>), Const(ConstArg), + Infer(InferArg), } impl GenericArg<'_> { @@ -267,6 +294,7 @@ impl GenericArg<'_> { GenericArg::Lifetime(l) => l.span, GenericArg::Type(t) => t.span, GenericArg::Const(c) => c.span, + GenericArg::Infer(i) => i.span, } } @@ -275,6 +303,7 @@ impl GenericArg<'_> { GenericArg::Lifetime(l) => l.hir_id, GenericArg::Type(t) => t.hir_id, GenericArg::Const(c) => c.value.hir_id, + GenericArg::Infer(i) => i.hir_id, } } @@ -291,6 +320,7 @@ impl GenericArg<'_> { GenericArg::Lifetime(_) => "lifetime", GenericArg::Type(_) => "type", GenericArg::Const(_) => "constant", + GenericArg::Infer(_) => "inferred", } } @@ -301,6 +331,7 @@ impl GenericArg<'_> { GenericArg::Const(_) => { ast::ParamKindOrd::Const { unordered: feats.unordered_const_ty_params() } } + GenericArg::Infer(_) => ast::ParamKindOrd::Infer, } } } @@ -342,27 +373,36 @@ impl GenericArgs<'_> { break; } GenericArg::Const(_) => {} + GenericArg::Infer(_) => {} } } } panic!("GenericArgs::inputs: not a `Fn(T) -> U`"); } - pub fn own_counts(&self) -> GenericParamCount { - // We could cache this as a property of `GenericParamCount`, but - // the aim is to refactor this away entirely eventually and the - // presence of this method will be a constant reminder. - let mut own_counts: GenericParamCount = Default::default(); + #[inline] + pub fn has_type_params(&self) -> bool { + self.args.iter().any(|arg| matches!(arg, GenericArg::Type(_))) + } - for arg in self.args { - match arg { - GenericArg::Lifetime(_) => own_counts.lifetimes += 1, - GenericArg::Type(_) => own_counts.types += 1, - GenericArg::Const(_) => own_counts.consts += 1, - }; - } + #[inline] + pub fn num_type_params(&self) -> usize { + self.args.iter().filter(|arg| matches!(arg, GenericArg::Type(_))).count() + } - own_counts + #[inline] + pub fn num_lifetime_params(&self) -> usize { + self.args.iter().filter(|arg| matches!(arg, GenericArg::Lifetime(_))).count() + } + + #[inline] + pub fn has_lifetime_params(&self) -> bool { + self.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) + } + + #[inline] + pub fn num_generic_params(&self) -> usize { + self.args.iter().filter(|arg| !matches!(arg, GenericArg::Lifetime(_))).count() } /// The span encompassing the text inside the surrounding brackets. @@ -485,6 +525,7 @@ pub struct GenericParamCount { pub lifetimes: usize, pub types: usize, pub consts: usize, + pub infer: usize, } /// Represents lifetimes and type parameters attached to a declaration @@ -3130,6 +3171,8 @@ pub enum Node<'hir> { Visibility(&'hir Visibility<'hir>), Crate(&'hir Mod<'hir>), + + Infer(&'hir InferArg), } impl<'hir> Node<'hir> { @@ -3198,6 +3241,7 @@ impl<'hir> Node<'hir> { | Node::Local(Local { hir_id, .. }) | Node::Lifetime(Lifetime { hir_id, .. }) | Node::Param(Param { hir_id, .. }) + | Node::Infer(InferArg { hir_id, .. }) | Node::GenericParam(GenericParam { hir_id, .. }) => Some(*hir_id), Node::TraitRef(TraitRef { hir_ref_id, .. }) => Some(*hir_ref_id), Node::PathSegment(PathSegment { hir_id, .. }) => *hir_id, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 711b62c4a3142..17835493cda62 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -436,11 +436,15 @@ pub trait Visitor<'v>: Sized { fn visit_label(&mut self, label: &'v Label) { walk_label(self, label) } + fn visit_infer(&mut self, inf: &'v InferArg) { + walk_inf(self, inf); + } fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) { match generic_arg { GenericArg::Lifetime(lt) => self.visit_lifetime(lt), GenericArg::Type(ty) => self.visit_ty(ty), GenericArg::Const(ct) => self.visit_anon_const(&ct.value), + GenericArg::Infer(inf) => self.visit_infer(inf), } } fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { @@ -747,6 +751,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) { } } +pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) { + visitor.visit_id(inf.hir_id); +} + pub fn walk_qpath<'v, V: Visitor<'v>>( visitor: &mut V, qpath: &'v QPath<'v>, diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 4177c2f8d525e..90ceb1d5c91ec 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -103,6 +103,7 @@ impl<'a> State<'a> { Node::TraitRef(a) => self.print_trait_ref(&a), Node::Binding(a) | Node::Pat(a) => self.print_pat(&a), Node::Arm(a) => self.print_arm(&a), + Node::Infer(_) => self.s.word("_"), Node::Block(a) => { // Containing cbox, will be closed by print-block at `}`. self.cbox(INDENT_UNIT); @@ -437,14 +438,14 @@ impl<'a> State<'a> { self.print_anon_const(e); self.s.word(")"); } - hir::TyKind::Infer => { - self.s.word("_"); - } hir::TyKind::Err => { self.popen(); self.s.word("/*ERROR*/"); self.pclose(); } + hir::TyKind::Infer => { + self.s.word("_"); + } } self.end() } @@ -1851,6 +1852,7 @@ impl<'a> State<'a> { GenericArg::Lifetime(_) => {} GenericArg::Type(ty) => s.print_type(ty), GenericArg::Const(ct) => s.print_anon_const(&ct.value), + GenericArg::Infer(_inf) => s.word("_"), }, ); } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index e504662bb5eae..052efa851f7cf 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -244,6 +244,11 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas hir_visit::walk_ty(self, t); } + fn visit_infer(&mut self, inf: &'tcx hir::InferArg) { + lint_callback!(self, check_infer, inf); + hir_visit::walk_inf(self, inf); + } + fn visit_name(&mut self, sp: Span, name: Symbol) { lint_callback!(self, check_name, sp, name); } diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index bbe17dcf4b736..2d047ac7a0814 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -33,6 +33,7 @@ macro_rules! late_lint_methods { fn check_expr(a: &$hir hir::Expr<$hir>); fn check_expr_post(a: &$hir hir::Expr<$hir>); fn check_ty(a: &$hir hir::Ty<$hir>); + fn check_infer(a: &$hir hir::InferArg); fn check_generic_arg(a: &$hir hir::GenericArg<$hir>); fn check_generic_param(a: &$hir hir::GenericParam<$hir>); fn check_generics(a: &$hir hir::Generics<$hir>); diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index 0eb0c3eca4e3f..5c166c74004a3 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -336,6 +336,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + fn visit_infer(&mut self, inf: &'hir InferArg) { + self.insert(inf.span, inf.hir_id, Node::Infer(inf)); + + self.with_parent(inf.hir_id, |this| { + intravisit::walk_inf(this, inf); + }); + } + fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) { self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr)); diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 1a3d875c5ba6b..b1606ef8f636b 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -276,6 +276,7 @@ impl<'hir> Map<'hir> { Node::Stmt(_) | Node::PathSegment(_) | Node::Ty(_) + | Node::Infer(_) | Node::TraitRef(_) | Node::Pat(_) | Node::Binding(_) @@ -871,6 +872,7 @@ impl<'hir> Map<'hir> { node: VisibilityKind::Restricted { ref path, .. }, .. }) => path.span, + Node::Infer(i) => i.span, Node::Visibility(v) => bug!("unexpected Visibility {:?}", v), Node::Local(local) => local.span, Node::MacroDef(macro_def) => macro_def.span, @@ -1118,6 +1120,7 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String { Some(Node::Param(_)) => node_str("param"), Some(Node::Arm(_)) => node_str("arm"), Some(Node::Block(_)) => node_str("block"), + Some(Node::Infer(_)) => node_str("infer"), Some(Node::Local(_)) => node_str("local"), Some(Node::Ctor(..)) => format!("ctor {}{}", path_str(), id_str), Some(Node::Lifetime(_)) => node_str("lifetime"), diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index d969f50c1d918..cd91ecdf2bad3 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1188,6 +1188,14 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { self.maybe_typeck_results = old_maybe_typeck_results; } + fn visit_generic_arg(&mut self, generic_arg: &'tcx hir::GenericArg<'tcx>) { + match generic_arg { + hir::GenericArg::Type(t) => self.visit_ty(t), + hir::GenericArg::Infer(inf) => self.visit_infer(inf), + hir::GenericArg::Lifetime(_) | hir::GenericArg::Const(_) => {} + } + } + fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) { self.span = hir_ty.span; if let Some(typeck_results) = self.maybe_typeck_results { @@ -1207,6 +1215,30 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { intravisit::walk_ty(self, hir_ty); } + fn visit_infer(&mut self, inf: &'tcx hir::InferArg) { + self.span = inf.span; + if let Some(typeck_results) = self.maybe_typeck_results { + if let Some(ty) = typeck_results.node_type_opt(inf.hir_id) { + if self.visit(ty).is_break() { + return; + } + } + } else { + let local_id = self.tcx.hir().local_def_id(inf.hir_id); + if let Some(did) = self.tcx.opt_const_param_of(local_id) { + if self.visit_def_id(did, "inferred", &"").is_break() { + return; + } + } + + // FIXME see above note for same issue. + if self.visit(rustc_typeck::hir_ty_to_ty(self.tcx, &inf.to_ty())).is_break() { + return; + } + } + intravisit::walk_inf(self, inf); + } + fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef<'tcx>) { self.span = trait_ref.path.span; if self.maybe_typeck_results.is_none() { @@ -1443,6 +1475,14 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a NestedVisitorMap::None } + fn visit_generic_arg(&mut self, generic_arg: &'v hir::GenericArg<'v>) { + match generic_arg { + hir::GenericArg::Type(t) => self.visit_ty(t), + hir::GenericArg::Infer(inf) => self.visit_ty(&inf.to_ty()), + hir::GenericArg::Lifetime(_) | hir::GenericArg::Const(_) => {} + } + } + fn visit_ty(&mut self, ty: &hir::Ty<'_>) { if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = ty.kind { if self.inner.path_is_private_type(path) { diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 4329477404298..e18dae0b8eebb 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -2550,6 +2550,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { GenericArg::Const(ct) => { self.visit_anon_const(&ct.value); } + GenericArg::Infer(inf) => { + self.visit_id(inf.hir_id); + if inf.kind.is_type() { + i += 1; + } + } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c0f63f40853da..536ebdef426b8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -622,6 +622,7 @@ symbols! { generator, generator_state, generators, + generic_arg_infer, generic_associated_types, generic_param_attrs, get_context, diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 456f2a908a8c1..eb6265dec89c0 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -39,8 +39,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); if let GenericParamDefKind::Const { .. } = param.kind { - if let GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. }) = arg { + if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. })) { err.help("const arguments cannot yet be inferred with `_`"); + if sess.is_nightly_build() { + err.help( + "add `#![feature(generic_arg_infer)]` to the crate attributes to enable", + ); + } } } @@ -249,14 +254,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (Some(&arg), Some(¶m)) => { match (arg, ¶m.kind, arg_count.explicit_late_bound) { (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _) - | (GenericArg::Type(_), GenericParamDefKind::Type { .. }, _) - | (GenericArg::Const(_), GenericParamDefKind::Const { .. }, _) => { + | ( + GenericArg::Type(_) | GenericArg::Infer(_), + GenericParamDefKind::Type { .. }, + _, + ) + | ( + GenericArg::Const(_) | GenericArg::Infer(_), + GenericParamDefKind::Const { .. }, + _, + ) => { substs.push(ctx.provided_kind(param, arg)); args.next(); params.next(); } ( - GenericArg::Type(_) | GenericArg::Const(_), + GenericArg::Infer(_) | GenericArg::Type(_) | GenericArg::Const(_), GenericParamDefKind::Lifetime, _, ) => { @@ -325,6 +338,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .features() .unordered_const_ty_params(), }, + GenericArg::Infer(_) => ParamKindOrd::Infer, }), Some(&format!( "reorder the arguments: {}: `<{}>`", @@ -446,8 +460,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let default_counts = gen_params.own_defaults(); let param_counts = gen_params.own_counts(); let named_type_param_count = param_counts.types - has_self as usize; - let arg_counts = gen_args.own_counts(); - let infer_lifetimes = gen_pos != GenericArgPosition::Type && arg_counts.lifetimes == 0; + let infer_lifetimes = + gen_pos != GenericArgPosition::Type && !gen_args.has_lifetime_params(); if gen_pos != GenericArgPosition::Type && !gen_args.bindings.is_empty() { Self::prohibit_assoc_ty_binding(tcx, gen_args.bindings[0].span); @@ -505,7 +519,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let min_expected_lifetime_args = if infer_lifetimes { 0 } else { param_counts.lifetimes }; let max_expected_lifetime_args = param_counts.lifetimes; - let num_provided_lifetime_args = arg_counts.lifetimes; + let num_provided_lifetime_args = gen_args.num_lifetime_params(); let lifetimes_correct = check_lifetime_args( min_expected_lifetime_args, @@ -576,14 +590,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { - default_counts.consts }; debug!("expected_min: {:?}", expected_min); - debug!("arg_counts.lifetimes: {:?}", arg_counts.lifetimes); + debug!("arg_counts.lifetimes: {:?}", gen_args.num_lifetime_params()); check_types_and_consts( expected_min, param_counts.consts + named_type_param_count, - arg_counts.consts + arg_counts.types, + gen_args.num_generic_params(), param_counts.lifetimes + has_self as usize, - arg_counts.lifetimes, + gen_args.num_lifetime_params(), ) }; @@ -622,7 +636,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .args .iter() .filter_map(|arg| match arg { - GenericArg::Type(_) | GenericArg::Const(_) => Some(arg.span()), + GenericArg::Infer(_) | GenericArg::Type(_) | GenericArg::Const(_) => { + Some(arg.span()) + } _ => None, }) .collect::>(); @@ -659,8 +675,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { position: GenericArgPosition, ) -> ExplicitLateBound { let param_counts = def.own_counts(); - let arg_counts = args.own_counts(); - let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0; + let infer_lifetimes = position != GenericArgPosition::Type && !args.has_lifetime_params(); if infer_lifetimes { return ExplicitLateBound::No; @@ -673,7 +688,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let span = args.args[0].span(); if position == GenericArgPosition::Value - && arg_counts.lifetimes != param_counts.lifetimes + && args.num_lifetime_params() != param_counts.lifetimes { let mut err = tcx.sess.struct_span_err(span, msg); err.span_note(span_late, note); diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index b82437120ce98..9871b14754e62 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -461,6 +461,43 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) .into() } + (&GenericParamDefKind::Const { has_default }, hir::GenericArg::Infer(inf)) => { + if has_default { + tcx.const_param_default(param.def_id).into() + } else if self.astconv.allow_ty_infer() { + // FIXME(const_generics): Actually infer parameter here? + todo!() + } else { + self.inferred_params.push(inf.span); + tcx.ty_error().into() + } + } + ( + &GenericParamDefKind::Type { has_default, .. }, + hir::GenericArg::Infer(inf), + ) => { + if has_default { + tcx.check_optional_stability( + param.def_id, + Some(arg.id()), + arg.span(), + None, + |_, _| { + // Default generic parameters may not be marked + // with stability attributes, i.e. when the + // default parameter was defined at the same time + // as the rest of the type. As such, we ignore missing + // stability attributes. + }, + ); + } + if self.astconv.allow_ty_infer() { + self.astconv.ast_ty_to_ty(&inf.to_ty()).into() + } else { + self.inferred_params.push(inf.span); + tcx.ty_error().into() + } + } _ => unreachable!(), } } @@ -1930,6 +1967,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { has_err = true; (ct.span, "const") } + hir::GenericArg::Infer(inf) => { + if err_for_ty { + continue; + } + has_err = true; + err_for_ty = true; + (inf.span, "generic") + } }; let mut err = struct_span_err!( self.tcx().sess, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 865e4ccc0b63f..f5776ae7cf66a 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -581,6 +581,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + pub fn node_ty_opt(&self, id: hir::HirId) -> Option> { + match self.typeck_results.borrow().node_types().get(id) { + Some(&t) => Some(t), + None if self.is_tainted_by_errors() => Some(self.tcx.ty_error()), + None => None, + } + } + /// Registers an obligation for checking later, during regionck, that `arg` is well-formed. pub fn register_wf_obligation( &self, @@ -1471,6 +1479,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => { self.fcx.const_arg_to_const(&ct.value, param.def_id).into() } + (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => { + self.fcx.ty_infer(Some(param), inf.span).into() + } + (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { + let tcx = self.fcx.tcx(); + self.fcx.ct_infer(tcx.type_of(param.def_id), Some(param), inf.span).into() + } _ => unreachable!(), } } diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index 75299bae5ddfd..3aceaba882d6c 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -366,6 +366,13 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => { self.cfcx.const_arg_to_const(&ct.value, param.def_id).into() } + (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => { + self.cfcx.ty_infer(Some(param), inf.span).into() + } + (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { + let tcx = self.cfcx.tcx(); + self.cfcx.ct_infer(tcx.type_of(param.def_id), Some(param), inf.span).into() + } _ => unreachable!(), } } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index 935bcc9f32e2b..e6eac16667d4e 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -331,6 +331,15 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { let ty = self.resolve(ty, &hir_ty.span); self.write_ty_to_typeck_results(hir_ty.hir_id, ty); } + + fn visit_infer(&mut self, inf: &'tcx hir::InferArg) { + intravisit::walk_inf(self, inf); + // Ignore cases where the inference is a const. + if let Some(ty) = self.fcx.node_ty_opt(inf.hir_id) { + let ty = self.resolve(ty, &inf.span); + self.write_ty_to_typeck_results(inf.hir_id, ty); + } + } } impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 46b3ec5cf40c7..997fdcefe037a 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -129,6 +129,16 @@ impl<'v> Visitor<'v> for PlaceholderHirTyCollector { } 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.0.push(inf.span); + intravisit::walk_inf(self, inf); + } + hir::GenericArg::Type(t) => self.visit_ty(t), + _ => {} + } + } } struct CollectItemTypesVisitor<'tcx> { @@ -1714,13 +1724,11 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { } fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool { - generic_args - .iter() - .filter_map(|arg| match arg { - hir::GenericArg::Type(ty) => Some(ty), - _ => None, - }) - .any(is_suggestable_infer_ty) + generic_args.iter().any(|arg| match arg { + hir::GenericArg::Type(ty) => is_suggestable_infer_ty(ty), + hir::GenericArg::Infer(_) => true, + _ => false, + }) } /// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 50e4ba4fe6c3e..96b3fa9aa0143 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -20,6 +20,9 @@ use super::{bad_placeholder_type, is_suggestable_infer_ty}; /// /// This should be called using the query `tcx.opt_const_param_of`. pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { + // FIXME(generic_arg_infer): allow for returning DefIds of inference of + // GenericArg::Infer below. This may require a change where GenericArg::Infer has some flag + // for const or type. use hir::*; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1a2852dc6c724..27c2f6cc87e17 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1768,6 +1768,7 @@ impl Clean for hir::GenericArgs<'_> { hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()), hir::GenericArg::Type(ty) => GenericArg::Type(ty.clean(cx)), hir::GenericArg::Const(ct) => GenericArg::Const(ct.clean(cx)), + hir::GenericArg::Infer(_inf) => GenericArg::Infer, }) .collect(), bindings: self.bindings.clean(cx), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 101d3b400c3df..2460fa127f116 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2007,6 +2007,7 @@ crate enum GenericArg { Lifetime(Lifetime), Type(Type), Const(Constant), + Infer, } #[derive(Clone, PartialEq, Eq, Debug, Hash)] diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 08499cef33ef1..cd74006530b44 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1424,6 +1424,7 @@ impl clean::GenericArg { clean::GenericArg::Lifetime(lt) => fmt::Display::fmt(<.print(), f), clean::GenericArg::Type(ty) => fmt::Display::fmt(&ty.print(cx), f), clean::GenericArg::Const(ct) => fmt::Display::fmt(&ct.print(cx.tcx()), f), + clean::GenericArg::Infer => fmt::Display::fmt("_", f), }) } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index bf8db79416b34..f3eeea6c6ae0b 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -140,6 +140,7 @@ impl FromWithTcx for GenericArg { Lifetime(l) => GenericArg::Lifetime(l.0.to_string()), Type(t) => GenericArg::Type(t.into_tcx(tcx)), Const(c) => GenericArg::Const(c.into_tcx(tcx)), + Infer => GenericArg::Infer, } } } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 6d9a5cb515a48..38ba87322c238 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -127,6 +127,7 @@ pub enum GenericArg { Lifetime(String), Type(Type), Const(Constant), + Infer, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] diff --git a/src/test/ui/const-generics/issues/issue-62878.full.stderr b/src/test/ui/const-generics/issues/issue-62878.full.stderr index 6e6aa19663302..08f6454fa2dfe 100644 --- a/src/test/ui/const-generics/issues/issue-62878.full.stderr +++ b/src/test/ui/const-generics/issues/issue-62878.full.stderr @@ -4,13 +4,13 @@ error[E0770]: the type of const parameters must not depend on other generic para LL | fn foo() {} | ^ the type must not depend on the parameter `N` -error[E0747]: type provided when a constant was expected - --> $DIR/issue-62878.rs:10:11 +error: constant expression depends on a generic parameter + --> $DIR/issue-62878.rs:10:14 | LL | foo::<_, {[1]}>(); - | ^ + | ^^^^^ | - = help: const arguments cannot yet be inferred with `_` + = note: this may fail depending on what value the parameter takes error[E0308]: mismatched types --> $DIR/issue-62878.rs:10:15 @@ -20,5 +20,5 @@ LL | foo::<_, {[1]}>(); error: aborting due to 3 previous errors -Some errors have detailed explanations: E0308, E0747, E0770. +Some errors have detailed explanations: E0308, E0770. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/issues/issue-62878.rs b/src/test/ui/const-generics/issues/issue-62878.rs index a70606c4a7d32..fb6257696b96d 100644 --- a/src/test/ui/const-generics/issues/issue-62878.rs +++ b/src/test/ui/const-generics/issues/issue-62878.rs @@ -1,5 +1,5 @@ // revisions: full min -#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, feature(const_generics, generic_arg_infer))] #![cfg_attr(full, allow(incomplete_features))] fn foo() {} @@ -8,6 +8,6 @@ fn foo() {} fn main() { foo::<_, {[1]}>(); - //[full]~^ ERROR type provided when a constant was expected - //[full]~| ERROR mismatched types + //[full]~^ ERROR mismatched types + //[full]~| ERROR constant expression } diff --git a/src/test/ui/const-generics/min_const_generics/inferred_const.rs b/src/test/ui/const-generics/min_const_generics/inferred_const.rs index dcd069ce3b0f4..57d6941587a43 100644 --- a/src/test/ui/const-generics/min_const_generics/inferred_const.rs +++ b/src/test/ui/const-generics/min_const_generics/inferred_const.rs @@ -1,8 +1,9 @@ -#![feature(min_const_generics)] -fn foo(data: [u32; N]) -> [u32; K] { +#![feature(generic_arg_infer)] +// run-pass + +fn foo(_data: [u32; N]) -> [u32; K] { [0; K] } fn main() { - let a = foo::<_, 2>([0, 1, 2]); - //~^ ERROR type provided when a constant was expected + let _a = foo::<_, 2>([0, 1, 2]); } diff --git a/src/test/ui/const-generics/min_const_generics/inferred_const.stderr b/src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr similarity index 54% rename from src/test/ui/const-generics/min_const_generics/inferred_const.stderr rename to src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr index e17105b2aa999..c17f02d58f325 100644 --- a/src/test/ui/const-generics/min_const_generics/inferred_const.stderr +++ b/src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr @@ -1,10 +1,11 @@ error[E0747]: type provided when a constant was expected - --> $DIR/inferred_const.rs:6:19 + --> $DIR/feature-gate-generic_arg_infer.rs:11:20 | -LL | let a = foo::<_, 2>([0, 1, 2]); - | ^ +LL | let _x = foo::<_>([1,2]); + | ^ | = help: const arguments cannot yet be inferred with `_` + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-generic_arg_infer.rs b/src/test/ui/feature-gates/feature-gate-generic_arg_infer.rs new file mode 100644 index 0000000000000..4729773b12ef0 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-generic_arg_infer.rs @@ -0,0 +1,13 @@ +// [feature] run-pass +// revisions: normal feature + +#![cfg_attr(feature, feature(generic_arg_infer))] + +fn foo(_: [u8; N]) -> [u8; N] { + [0; N] +} + +fn main() { + let _x = foo::<_>([1,2]); + //[normal]~^ ERROR: type provided when a constant was expected +} diff --git a/src/test/ui/inference/infer-arg-test.rs b/src/test/ui/inference/infer-arg-test.rs new file mode 100644 index 0000000000000..1b67ccd6c4337 --- /dev/null +++ b/src/test/ui/inference/infer-arg-test.rs @@ -0,0 +1,24 @@ +#![feature(generic_arg_infer)] + +struct All<'a, T, const N: usize> { + v: &'a T, +} + +struct BadInfer<_>; +//~^ ERROR expected identifier +//~| ERROR parameter `_` is never used + +fn all_fn<'a, T, const N: usize>() {} + +fn bad_infer_fn<_>() {} +//~^ ERROR expected identifier + + +fn main() { + let a: All<_, _, _>; + all_fn(); + let v: [u8; _]; + //~^ ERROR in expressions + let v: [u8; 10] = [0; _]; + //~^ ERROR in expressions +} diff --git a/src/test/ui/inference/infer-arg-test.stderr b/src/test/ui/inference/infer-arg-test.stderr new file mode 100644 index 0000000000000..30e171eac2121 --- /dev/null +++ b/src/test/ui/inference/infer-arg-test.stderr @@ -0,0 +1,36 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/infer-arg-test.rs:7:17 + | +LL | struct BadInfer<_>; + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/infer-arg-test.rs:13:17 + | +LL | fn bad_infer_fn<_>() {} + | ^ expected identifier, found reserved identifier + +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/infer-arg-test.rs:20:15 + | +LL | let v: [u8; _]; + | ^ `_` not allowed here + +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/infer-arg-test.rs:22:25 + | +LL | let v: [u8; 10] = [0; _]; + | ^ `_` not allowed here + +error[E0392]: parameter `_` is never used + --> $DIR/infer-arg-test.rs:7:17 + | +LL | struct BadInfer<_>; + | ^ unused parameter + | + = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `_` to be a const parameter, use `const _: usize` instead + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0392`. diff --git a/src/test/ui/object-lifetime-default-inferred.rs b/src/test/ui/object-lifetime-default-inferred.rs new file mode 100644 index 0000000000000..8a1156b8fc8ad --- /dev/null +++ b/src/test/ui/object-lifetime-default-inferred.rs @@ -0,0 +1,35 @@ +// run-pass +// Test that even with prior inferred parameters, object lifetimes of objects after are still +// valid. + +// pretty-expanded FIXME #23616 + +#![allow(dead_code)] +#![feature(generic_arg_infer)] + +trait Test { + fn foo(&self) { } +} + +struct Foo; +impl Test for Foo {} + +struct SomeStruct<'a> { + t: &'a dyn Test, + u: &'a (dyn Test+'a), +} + +fn a<'a, const N: usize>(_: [u8; N], t: &'a (dyn Test+'a), mut ss: SomeStruct<'a>) { + ss.t = t; +} + +fn b<'a, T>(_: T, t: &'a (dyn Test+'a), mut ss: SomeStruct<'a>) { + ss.u = t; +} + +fn main() { + // Inside a function body, we can just infer both + // lifetimes, to allow &'tmp (Display+'static). + a::<_>([], &Foo as &dyn Test, SomeStruct{t:&Foo,u:&Foo}); + b::<_>(0u8, &Foo as &dyn Test, SomeStruct{t:&Foo,u:&Foo}); +} diff --git a/src/test/ui/parser/issue-14303-fncall.stderr b/src/test/ui/parser/issue-14303-fncall.full.stderr similarity index 86% rename from src/test/ui/parser/issue-14303-fncall.stderr rename to src/test/ui/parser/issue-14303-fncall.full.stderr index cdda0d001c7dc..02af61e853967 100644 --- a/src/test/ui/parser/issue-14303-fncall.stderr +++ b/src/test/ui/parser/issue-14303-fncall.full.stderr @@ -1,5 +1,5 @@ error[E0747]: type provided when a lifetime was expected - --> $DIR/issue-14303-fncall.rs:13:26 + --> $DIR/issue-14303-fncall.rs:16:26 | LL | .collect::>>(); | ^ diff --git a/src/test/ui/parser/issue-14303-fncall.generic_arg.stderr b/src/test/ui/parser/issue-14303-fncall.generic_arg.stderr new file mode 100644 index 0000000000000..9f3359b3f68a9 --- /dev/null +++ b/src/test/ui/parser/issue-14303-fncall.generic_arg.stderr @@ -0,0 +1,9 @@ +error[E0747]: inferred provided when a lifetime was expected + --> $DIR/issue-14303-fncall.rs:16:26 + | +LL | .collect::>>(); + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/parser/issue-14303-fncall.rs b/src/test/ui/parser/issue-14303-fncall.rs index 46ece84d69e45..976a79a59b1f8 100644 --- a/src/test/ui/parser/issue-14303-fncall.rs +++ b/src/test/ui/parser/issue-14303-fncall.rs @@ -1,6 +1,9 @@ -// can't run rustfix because it doesn't handle multipart suggestions correctly +// revisions: full generic_arg // compile-flags: -Zborrowck=mir +// can't run rustfix because it doesn't handle multipart suggestions correctly // we need the above to avoid ast borrowck failure in recovered code +#![cfg_attr(generic_arg, feature(generic_arg_infer))] + struct S<'a, T> { a: &'a T, @@ -11,7 +14,8 @@ fn foo<'a, 'b>(start: &'a usize, end: &'a usize) { let _x = (*start..*end) .map(|x| S { a: start, b: end }) .collect::>>(); - //~^ ERROR type provided when a lifetime was expected + //[generic_arg]~^ ERROR inferred provided when a lifetime was expected + //[full]~^^ ERROR type provided when a lifetime was expected } fn main() {} diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.full.stderr similarity index 85% rename from src/test/ui/span/issue-42234-unknown-receiver-type.stderr rename to src/test/ui/span/issue-42234-unknown-receiver-type.full.stderr index c64c5b1c28f41..278d049224401 100644 --- a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr +++ b/src/test/ui/span/issue-42234-unknown-receiver-type.full.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed for `Option<_>` - --> $DIR/issue-42234-unknown-receiver-type.rs:7:7 + --> $DIR/issue-42234-unknown-receiver-type.rs:10:7 | LL | let x: Option<_> = None; | - consider giving `x` the explicit type `Option<_>`, where the type parameter `T` is specified @@ -9,7 +9,7 @@ LL | x.unwrap().method_that_could_exist_on_some_type(); = note: type must be known at this point error[E0282]: type annotations needed - --> $DIR/issue-42234-unknown-receiver-type.rs:13:10 + --> $DIR/issue-42234-unknown-receiver-type.rs:16:10 | LL | .sum::<_>() | ^^^ cannot infer type diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr new file mode 100644 index 0000000000000..8d4ed4aea6a6c --- /dev/null +++ b/src/test/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr @@ -0,0 +1,21 @@ +error[E0282]: type annotations needed for `Option<_>` + --> $DIR/issue-42234-unknown-receiver-type.rs:10:7 + | +LL | let x: Option<_> = None; + | - consider giving `x` the explicit type `Option<_>`, where the type parameter `T` is specified +LL | x.unwrap().method_that_could_exist_on_some_type(); + | ^^^^^^ cannot infer type for type parameter `T` + | + = note: type must be known at this point + +error[E0282]: type annotations needed + --> $DIR/issue-42234-unknown-receiver-type.rs:16:16 + | +LL | .sum::<_>() + | ^ cannot infer type for type parameter `S` declared on the associated function `sum` + | + = note: type must be known at this point + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.rs b/src/test/ui/span/issue-42234-unknown-receiver-type.rs index d3292bbecbaaa..15b00de44b933 100644 --- a/src/test/ui/span/issue-42234-unknown-receiver-type.rs +++ b/src/test/ui/span/issue-42234-unknown-receiver-type.rs @@ -1,3 +1,6 @@ +// revisions: full generic_arg +#![cfg_attr(generic_arg, feature(generic_arg_infer))] + // When the type of a method call's receiver is unknown, the span should point // to the receiver (and not the entire call, as was previously the case before // the fix of which this tests). diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index 9a040ca572af5..ad4898d1ccbb5 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -5,7 +5,7 @@ use std::collections::BTreeMap; use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; -use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, walk_inf, NestedVisitorMap, Visitor}; use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; @@ -295,6 +295,14 @@ impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> { walk_ty(self, t); } + fn visit_infer(&mut self, inf: &'tcx hir::InferArg) { + if let Some(target) = ImplicitHasherType::new(self.cx, &inf.to_ty()) { + self.found.push(target); + } + + walk_inf(self, inf); + } + fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None } diff --git a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs index d8c4b67520d11..b438d680d2cbd 100644 --- a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; -use rustc_hir::intravisit::{walk_ty, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{walk_ty, walk_inf, NestedVisitorMap, Visitor}; use rustc_hir::{GenericParamKind, TyKind}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; @@ -39,6 +39,11 @@ struct TypeComplexityVisitor { impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor { type Map = Map<'tcx>; + fn visit_infer(&mut self, inf: &'tcx hir::InferArg) { + self.score += 1; + walk_inf(self, inf); + } + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) { let (add_score, sub_nest) = match ty.kind { // _, &x and *x have only small overhead; don't mess with nesting level diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index 71117e967e319..d5ee717accd26 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -8,8 +8,9 @@ use rustc_hir::{ self as hir, def::{CtorOf, DefKind, Res}, def_id::LocalDefId, - intravisit::{walk_ty, NestedVisitorMap, Visitor}, - Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Path, QPath, TyKind, + intravisit::{walk_ty, walk_inf, NestedVisitorMap, Visitor}, + Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Path, + QPath, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; @@ -263,6 +264,11 @@ struct SkipTyCollector { impl<'tcx> Visitor<'tcx> for SkipTyCollector { type Map = Map<'tcx>; + fn visit_infer(&mut self, inf: &hir::InferArg) { + self.types_to_skip.push(inf.hir_id); + + walk_inf(self, inf) + } fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) { self.types_to_skip.push(hir_ty.hir_id); diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index a21ad42c0617e..6ea360a88a63e 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -288,6 +288,8 @@ impl HirEqInterExpr<'_, '_, '_> { (GenericArg::Const(l), GenericArg::Const(r)) => self.eq_body(l.value.body, r.value.body), (GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt), (GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty, r_ty), + (GenericArg::Infer(l_inf), GenericArg::Infer(r_inf)) => + self.eq_ty(&l_inf.to_ty(), &r_inf.to_ty()), _ => false, } } @@ -885,7 +887,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_ty(&mut self, ty: &Ty<'_>) { std::mem::discriminant(&ty.kind).hash(&mut self.s); - match ty.kind { + self.hash_tykind(&ty.kind); + } + + pub fn hash_tykind(&mut self, ty: &TyKind<'_>) { + match ty { TyKind::Slice(ty) => { self.hash_ty(ty); }, @@ -898,7 +904,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { mut_ty.mutbl.hash(&mut self.s); }, TyKind::Rptr(lifetime, ref mut_ty) => { - self.hash_lifetime(lifetime); + self.hash_lifetime(*lifetime); self.hash_ty(mut_ty.ty); mut_ty.mutbl.hash(&mut self.s); }, @@ -918,7 +924,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { bfn.decl.c_variadic.hash(&mut self.s); }, TyKind::Tup(ty_list) => { - for ty in ty_list { + for ty in *ty_list { self.hash_ty(ty); } }, @@ -927,7 +933,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_generic_args(arg_list); }, TyKind::TraitObject(_, lifetime, _) => { - self.hash_lifetime(lifetime); + self.hash_lifetime(*lifetime); }, TyKind::Typeof(anon_const) => { self.hash_body(anon_const.body); @@ -949,6 +955,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { GenericArg::Lifetime(l) => self.hash_lifetime(l), GenericArg::Type(ref ty) => self.hash_ty(ty), GenericArg::Const(ref ca) => self.hash_body(ca.value.body), + GenericArg::Infer(ref inf) => self.hash_ty(&inf.to_ty()), } } } diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 523d55219ab69..e914dc1c222f6 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -180,7 +180,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } // FIXME: Per https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/at/struct.At.html#method.normalize -// this function can be removed once the `normalizie` method does not panic when normalization does +// this function can be removed once the `normalize` method does not panic when normalization does // not succeed /// Checks if `Ty` is normalizable. This function is useful /// to avoid crashes on `layout_of`.