about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkadmin <julianknodt@gmail.com>2021-04-24 21:41:57 +0000
committerkadmin <julianknodt@gmail.com>2021-07-25 07:28:51 +0000
commit417b098cfc493a9b803b4ffbf6b74fc4f8e76f3d (patch)
tree613cc0e82fa1f34794abc8c6795c8cbdac57c1c3
parent71a6c7c80398143a67e27b01412f4b2ec12bde8b (diff)
downloadrust-417b098cfc493a9b803b4ffbf6b74fc4f8e76f3d.tar.gz
rust-417b098cfc493a9b803b4ffbf6b74fc4f8e76f3d.zip
Add generic arg infer
-rw-r--r--compiler/rustc_ast/src/ast.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs87
-rw-r--r--compiler/rustc_hir/src/hir.rs23
-rw-r--r--compiler/rustc_hir/src/intravisit.rs13
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs8
-rw-r--r--compiler/rustc_middle/src/hir/map/collector.rs8
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs3
-rw-r--r--compiler/rustc_middle/src/query/mod.rs5
-rw-r--r--compiler/rustc_privacy/src/lib.rs25
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs4
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs43
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs42
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs6
-rw-r--r--compiler/rustc_typeck/src/check/method/confirm.rs6
-rw-r--r--compiler/rustc_typeck/src/collect.rs21
-rw-r--r--src/librustdoc/clean/mod.rs1
-rw-r--r--src/librustdoc/clean/types.rs1
-rw-r--r--src/librustdoc/html/format.rs1
-rw-r--r--src/librustdoc/json/conversions.rs1
-rw-r--r--src/rustdoc-json-types/lib.rs1
-rw-r--r--src/test/ui/const-generics/issues/issue-62878.full.stderr10
-rw-r--r--src/test/ui/const-generics/issues/issue-62878.rs4
-rw-r--r--src/test/ui/const-generics/min_const_generics/inferred_const.rs8
-rw-r--r--src/test/ui/const-generics/min_const_generics/inferred_const.stderr11
-rw-r--r--src/test/ui/parser/issue-14303-fncall.rs2
-rw-r--r--src/test/ui/parser/issue-14303-fncall.stderr2
-rw-r--r--src/test/ui/privacy/associated-item-privacy-trait.stderr13
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs11
28 files changed, 270 insertions, 94 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index f851725058d..5bffc94364d 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -336,6 +336,7 @@ 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,
 }
 
 impl Ord for ParamKindOrd {
@@ -343,7 +344,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 +372,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 d4caba92416..c7a477fedc6 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1218,48 +1218,55 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         match arg {
             ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
             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 => {
+                        let hir_id = self.lower_node_id(ty.id);
+                        return GenericArg::Infer(hir::InferArg { hir_id, span: ty.span });
+                    }
+                    // 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_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index cacf1aeacd4..140219287b1 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -253,11 +253,24 @@ pub struct ConstArg {
     pub span: Span,
 }
 
+#[derive(Encodable, Debug, HashStable_Generic)]
+pub struct InferArg {
+    pub hir_id: HirId,
+    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<'_> {
@@ -266,6 +279,7 @@ impl GenericArg<'_> {
             GenericArg::Lifetime(l) => l.span,
             GenericArg::Type(t) => t.span,
             GenericArg::Const(c) => c.span,
+            GenericArg::Infer(i) => i.span,
         }
     }
 
@@ -274,6 +288,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,
         }
     }
 
@@ -290,6 +305,7 @@ impl GenericArg<'_> {
             GenericArg::Lifetime(_) => "lifetime",
             GenericArg::Type(_) => "type",
             GenericArg::Const(_) => "constant",
+            GenericArg::Infer(_) => "inferred",
         }
     }
 
@@ -300,6 +316,7 @@ impl GenericArg<'_> {
             GenericArg::Const(_) => {
                 ast::ParamKindOrd::Const { unordered: feats.unordered_const_ty_params() }
             }
+            GenericArg::Infer(_) => ast::ParamKindOrd::Infer,
         }
     }
 }
@@ -341,6 +358,7 @@ impl GenericArgs<'_> {
                         break;
                     }
                     GenericArg::Const(_) => {}
+                    GenericArg::Infer(_) => {}
                 }
             }
         }
@@ -358,6 +376,7 @@ impl GenericArgs<'_> {
                 GenericArg::Lifetime(_) => own_counts.lifetimes += 1,
                 GenericArg::Type(_) => own_counts.types += 1,
                 GenericArg::Const(_) => own_counts.consts += 1,
+                GenericArg::Infer(_) => own_counts.infer += 1,
             };
         }
 
@@ -484,6 +503,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
@@ -2987,6 +3007,8 @@ pub enum Node<'hir> {
     Visibility(&'hir Visibility<'hir>),
 
     Crate(&'hir Mod<'hir>),
+
+    Infer(&'hir InferArg),
 }
 
 impl<'hir> Node<'hir> {
@@ -3055,6 +3077,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 c08f1f53218..dc54c55341e 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -436,13 +436,22 @@ 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) {
+        self.visit_id(inf.hir_id);
+    }
     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 tcx(&self) -> Option<&TyCtxt<'tcx>> {
+        None
+    }
+    */
     fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
         walk_lifetime(self, lifetime)
     }
@@ -746,6 +755,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 5c1739b1ab9..d47bef4379c 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.print_string("_", ast::StrStyle::Cooked),
             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_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs
index 8ffd98326f1..75dff288d78 100644
--- a/compiler/rustc_middle/src/hir/map/collector.rs
+++ b/compiler/rustc_middle/src/hir/map/collector.rs
@@ -404,6 +404,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 ecd370b2404..c1f2b767e78 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -272,6 +272,7 @@ impl<'hir> Map<'hir> {
                 GenericParamKind::Type { .. } => DefKind::TyParam,
                 GenericParamKind::Const { .. } => DefKind::ConstParam,
             },
+            Node::Infer(_) => todo!(),
             Node::Crate(_) => DefKind::Mod,
             Node::Stmt(_)
             | Node::PathSegment(_)
@@ -882,6 +883,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,
@@ -1129,6 +1131,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_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 0908b6a1763..0395082fa65 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -133,6 +133,11 @@ rustc_queries! {
         cache_on_disk_if { key.is_local() }
     }
 
+    query generic_arg_for_infer_arg(key: DefId) -> hir::GenericArg<'tcx> {
+        desc { |tcx| "computes concrete type for inference, `{}`", tcx.def_path_str(key) }
+        storage(ArenaCacheSelector<'tcx>)
+    }
+
     /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
     /// predicates (where-clauses) that must be proven true in order
     /// to reference it. This is almost always the "predicates query"
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index d969f50c1d9..f4bdaffe3f7 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1188,6 +1188,23 @@ 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.span = inf.span;
+                let parent_hir_id = self.tcx.hir().get_parent_node(inf.hir_id);
+                if let Some(typeck_results) = self.maybe_typeck_results {
+                    let node_substs = typeck_results.node_substs(parent_hir_id);
+                    for ty in node_substs.types() {
+                        self.visit(ty);
+                    }
+                }
+            }
+            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 {
@@ -1443,6 +1460,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 ca7cdc4caf5..26e2efc2552 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -2557,6 +2557,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 GenericArg::Const(ct) => {
                     self.visit_anon_const(&ct.value);
                 }
+                GenericArg::Infer(inf) => {
+                    self.visit_id(inf.hir_id);
+                    i += 1;
+                }
             }
         }
 
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 456f2a908a8..a227d2f2337 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -18,6 +18,23 @@ use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
 use rustc_span::{symbol::kw, MultiSpan, Span};
 use smallvec::SmallVec;
 
+/*
+pub fn generic_arg_for_infer_arg<'tcx>(tcx: TyCtxt<'tcx>, did: LocalDefId) -> GenericArg<'tcx> {
+    todo!()
+    let hir_id = tcx.hir().local_def_id_to_hir_id(did);
+    let arg = match tcx.hir().get(hir_id) {
+        hir::Node::GenericParam(hir::GenericParam {
+            kind: hir::GenericParamKind::Const { ty: _, default: _ },
+            ..
+        }) => todo!(),
+        _ => bug!("Expected GenericParam for generic_arg_for_infer_arg"),
+    };
+
+    assert!(!matches!(arg, GenericArg::Infer(_)));
+    arg
+}
+*/
+
 impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     /// Report an error that a generic argument did not match the generic parameter that was
     /// expected.
@@ -39,7 +56,10 @@ 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, .. }) | GenericArg::Infer(_)
+            ) {
                 err.help("const arguments cannot yet be inferred with `_`");
             }
         }
@@ -249,14 +269,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     (Some(&arg), Some(&param)) => {
                         match (arg, &param.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 +353,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                                     .features()
                                                     .unordered_const_ty_params(),
                                             },
+                                            GenericArg::Infer(_) => ParamKindOrd::Infer,
                                         }),
                                         Some(&format!(
                                             "reorder the arguments: {}: `<{}>`",
@@ -581,7 +610,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             check_types_and_consts(
                 expected_min,
                 param_counts.consts + named_type_param_count,
-                arg_counts.consts + arg_counts.types,
+                arg_counts.consts + arg_counts.types + arg_counts.infer,
                 param_counts.lifetimes + has_self as usize,
                 arg_counts.lifetimes,
             )
@@ -622,7 +651,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::<Vec<_>>();
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index f55e274ef8e..d80eb26f6c2 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -461,6 +461,40 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         )
                         .into()
                     }
+                    (&GenericParamDefKind::Const { has_default }, hir::GenericArg::Infer(inf)) => {
+                        if has_default {
+                            // FIXME(const_generics): Actually infer parameter here?
+                            tcx.const_param_default(param.def_id).into()
+                        } 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(),
+                                |_, _| {
+                                    // 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!(),
                 }
             }
@@ -1922,6 +1956,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, "inferred")
+                    }
                 };
                 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 865e4ccc0b6..3a88fc5587a 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -1471,6 +1471,12 @@ 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.to_ty(&inf.to_ty()).into()
+                    }
+                    (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
+                        self.fcx.var_for_def(inf.span, param)
+                    }
                     _ => unreachable!(),
                 }
             }
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs
index 75299bae5dd..3224fe362cb 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_typeck/src/check/method/confirm.rs
@@ -366,6 +366,12 @@ 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.to_ty(&inf.to_ty()).into()
+                    }
+                    (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
+                        self.cfcx.var_for_def(inf.span, param)
+                    }
                     _ => unreachable!(),
                 }
             }
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 46b3ec5cf40..0b3fe82605c 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -129,6 +129,15 @@ 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);
+            }
+            hir::GenericArg::Type(t) => self.visit_ty(t),
+            _ => {}
+        }
+    }
 }
 
 struct CollectItemTypesVisitor<'tcx> {
@@ -1714,13 +1723,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/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 1a2852dc6c7..27c2f6cc87e 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1768,6 +1768,7 @@ impl Clean<GenericArgs> 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 2fd2d14bcab..da883d8057d 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 08499cef33e..cd74006530b 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(&lt.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 bf8db79416b..f3eeea6c6ae 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -140,6 +140,7 @@ impl FromWithTcx<clean::GenericArg> 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 6d9a5cb515a..38ba87322c2 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 6e6aa196633..08f6454fa2d 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<const N: usize, const A: [u8; N]>() {}
    |                                      ^ 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 a70606c4a7d..fae57b37773 100644
--- a/src/test/ui/const-generics/issues/issue-62878.rs
+++ b/src/test/ui/const-generics/issues/issue-62878.rs
@@ -8,6 +8,6 @@ fn foo<const N: usize, const A: [u8; N]>() {}
 
 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 dcd069ce3b0..f5800d10971 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,8 @@
-#![feature(min_const_generics)]
-fn foo<const N: usize, const K: usize>(data: [u32; N]) -> [u32; K] {
+// run-pass
+
+fn foo<const N: usize, const K: usize>(_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/const-generics/min_const_generics/inferred_const.stderr
deleted file mode 100644
index e17105b2aa9..00000000000
--- a/src/test/ui/const-generics/min_const_generics/inferred_const.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0747]: type provided when a constant was expected
-  --> $DIR/inferred_const.rs:6:19
-   |
-LL |     let a = foo::<_, 2>([0, 1, 2]);
-   |                   ^
-   |
-   = help: const arguments cannot yet be inferred with `_`
-
-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 46ece84d69e..1757baec70f 100644
--- a/src/test/ui/parser/issue-14303-fncall.rs
+++ b/src/test/ui/parser/issue-14303-fncall.rs
@@ -11,7 +11,7 @@ fn foo<'a, 'b>(start: &'a usize, end: &'a usize) {
     let _x = (*start..*end)
         .map(|x| S { a: start, b: end })
         .collect::<Vec<S<_, 'a>>>();
-        //~^ ERROR type provided when a lifetime was expected
+        //~^ ERROR inferred provided when a lifetime was expected
 }
 
 fn main() {}
diff --git a/src/test/ui/parser/issue-14303-fncall.stderr b/src/test/ui/parser/issue-14303-fncall.stderr
index cdda0d001c7..a039eca0bfd 100644
--- a/src/test/ui/parser/issue-14303-fncall.stderr
+++ b/src/test/ui/parser/issue-14303-fncall.stderr
@@ -1,4 +1,4 @@
-error[E0747]: type provided when a lifetime was expected
+error[E0747]: inferred provided when a lifetime was expected
   --> $DIR/issue-14303-fncall.rs:13:26
    |
 LL |         .collect::<Vec<S<_, 'a>>>();
diff --git a/src/test/ui/privacy/associated-item-privacy-trait.stderr b/src/test/ui/privacy/associated-item-privacy-trait.stderr
index 3a42415e474..1b6e27fa169 100644
--- a/src/test/ui/privacy/associated-item-privacy-trait.stderr
+++ b/src/test/ui/privacy/associated-item-privacy-trait.stderr
@@ -274,17 +274,6 @@ LL |     priv_parent_substs::mac!();
    = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: type `priv_parent_substs::Priv` is private
-  --> $DIR/associated-item-privacy-trait.rs:117:30
-   |
-LL |         let _: <Pub as PubTr<_>>::AssocTy;
-   |                              ^ private type
-...
-LL |     priv_parent_substs::mac!();
-   |     --------------------------- in this macro invocation
-   |
-   = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: type `priv_parent_substs::Priv` is private
   --> $DIR/associated-item-privacy-trait.rs:119:17
    |
 LL |         let _: <Priv as PubTr<_>>::AssocTy;
@@ -328,5 +317,5 @@ LL |     priv_parent_substs::mac!();
    |
    = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 30 previous errors
+error: aborting due to 29 previous errors
 
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index a21ad42c061..63737955f09 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -885,7 +885,15 @@ 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_infer(&mut self) {
+        "_".hash(&mut self.s);
+    }
+
+    pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
+        match ty {
             TyKind::Slice(ty) => {
                 self.hash_ty(ty);
             },
@@ -949,6 +957,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_infer(),
             }
         }
     }