Skip to content

Commit

Permalink
Actually infer args in visitors
Browse files Browse the repository at this point in the history
  • Loading branch information
JulianKnodt committed Jul 26, 2021
1 parent 3605675 commit 8759f00
Show file tree
Hide file tree
Showing 30 changed files with 257 additions and 97 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@ 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,
}

Expand Down
10 changes: 7 additions & 3 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -1219,9 +1219,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
ast::GenericArg::Type(ty) => {
match ty.kind {
TyKind::Infer => {
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 });
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
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,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
// -------------------------------------------------------------------------
Expand Down
49 changes: 35 additions & 14 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,23 @@ 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,
}

Expand Down Expand Up @@ -365,22 +379,29 @@ impl GenericArgs<'_> {
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,
GenericArg::Infer(_) => own_counts.infer += 1,
};
}
#[inline]
pub fn num_type_params(&self) -> usize {
self.args.iter().filter(|arg| matches!(arg, GenericArg::Type(_))).count()
}

#[inline]
pub fn num_lifetime_params(&self) -> usize {
self.args.iter().filter(|arg| matches!(arg, GenericArg::Lifetime(_))).count()
}

own_counts
#[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.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +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::Infer(_) => self.s.word("_"),
Node::Block(a) => {
// Containing cbox, will be closed by print-block at `}`.
self.cbox(INDENT_UNIT);
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_privacy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,13 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
}
}
} 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;
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_resolve/src/late/lifetimes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2559,7 +2559,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
GenericArg::Infer(inf) => {
self.visit_id(inf.hir_id);
i += 1;
if inf.kind.is_type() {
i += 1;
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,7 @@ symbols! {
generator,
generator_state,
generators,
generic_arg_infer,
generic_associated_types,
generic_param_attrs,
get_context,
Expand Down
27 changes: 14 additions & 13 deletions compiler/rustc_typeck/src/astconv/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);

if let GenericParamDefKind::Const { .. } = param.kind {
if matches!(
arg,
GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. }) | GenericArg::Infer(_)
) {
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",
);
}
}
}

Expand Down Expand Up @@ -458,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);
Expand Down Expand Up @@ -517,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,
Expand Down Expand Up @@ -588,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 + arg_counts.infer,
gen_args.num_generic_params(),
param_counts.lifetimes + has_self as usize,
arg_counts.lifetimes,
gen_args.num_lifetime_params(),
)
};

Expand Down Expand Up @@ -673,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;
Expand All @@ -687,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);
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_typeck/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -463,8 +463,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
(&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 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()
Expand Down Expand Up @@ -1963,7 +1965,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
has_err = true;
err_for_ty = true;
(inf.span, "inferred")
(inf.span, "generic")
}
};
let mut err = struct_span_err!(
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1480,10 +1480,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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()
self.fcx.ty_infer(Some(param), inf.span).into()
}
(GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
self.fcx.var_for_def(inf.span, param)
let tcx = self.fcx.tcx();
self.fcx.ct_infer(tcx.type_of(param.def_id), Some(param), inf.span).into()
}
_ => unreachable!(),
}
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_typeck/src/check/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,10 +367,11 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
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()
self.cfcx.ty_infer(Some(param), inf.span).into()
}
(GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
self.cfcx.var_for_def(inf.span, param)
let tcx = self.cfcx.tcx();
self.cfcx.ct_infer(tcx.type_of(param.def_id), Some(param), inf.span).into()
}
_ => unreachable!(),
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_typeck/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<DefId> {
// 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);

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/const-generics/issues/issue-62878.rs
Original file line number Diff line number Diff line change
@@ -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<const N: usize, const A: [u8; N]>() {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![feature(generic_arg_infer)]
// run-pass

fn foo<const N: usize, const K: usize>(_data: [u32; N]) -> [u32; K] {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0747]: type provided when a constant was expected
--> $DIR/feature-gate-generic_arg_infer.rs:11:20
|
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

For more information about this error, try `rustc --explain E0747`.
13 changes: 13 additions & 0 deletions src/test/ui/feature-gates/feature-gate-generic_arg_infer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// [feature] run-pass
// revisions: normal feature

#![cfg_attr(feature, feature(generic_arg_infer))]

fn foo<const N: usize>(_: [u8; N]) -> [u8; N] {
[0; N]
}

fn main() {
let _x = foo::<_>([1,2]);
//[normal]~^ ERROR: type provided when a constant was expected
}
24 changes: 24 additions & 0 deletions src/test/ui/inference/infer-arg-test.rs
Original file line number Diff line number Diff line change
@@ -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
}
36 changes: 36 additions & 0 deletions src/test/ui/inference/infer-arg-test.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 8759f00

Please sign in to comment.