Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hir::GenericArg::Infer #83484

Merged
merged 3 commits into from
Jul 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,14 +336,17 @@ 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,
JulianKnodt marked this conversation as resolved.
Show resolved Hide resolved
}

impl Ord for ParamKindOrd {
fn cmp(&self, other: &Self) -> Ordering {
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.
Expand Down Expand Up @@ -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),
}
}
}
Expand Down
93 changes: 52 additions & 41 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 @@ -1218,48 +1218,59 @@ 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 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))
}
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
70 changes: 57 additions & 13 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,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<'_> {
Expand All @@ -266,6 +293,7 @@ impl GenericArg<'_> {
GenericArg::Lifetime(l) => l.span,
GenericArg::Type(t) => t.span,
GenericArg::Const(c) => c.span,
GenericArg::Infer(i) => i.span,
}
}

Expand All @@ -274,6 +302,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,
}
}

Expand All @@ -290,6 +319,7 @@ impl GenericArg<'_> {
GenericArg::Lifetime(_) => "lifetime",
GenericArg::Type(_) => "type",
GenericArg::Const(_) => "constant",
GenericArg::Infer(_) => "inferred",
}
}

Expand All @@ -300,6 +330,7 @@ impl GenericArg<'_> {
GenericArg::Const(_) => {
ast::ParamKindOrd::Const { unordered: feats.unordered_const_ty_params() }
}
GenericArg::Infer(_) => ast::ParamKindOrd::Infer,
}
}
}
Expand Down Expand Up @@ -341,27 +372,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.
Expand Down Expand Up @@ -484,6 +524,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
Expand Down Expand Up @@ -2987,6 +3028,8 @@ pub enum Node<'hir> {
Visibility(&'hir Visibility<'hir>),

Crate(&'hir Mod<'hir>),

Infer(&'hir InferArg),
}

impl<'hir> Node<'hir> {
Expand Down Expand Up @@ -3055,6 +3098,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,
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -746,6 +750,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>,
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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()
}
Expand Down Expand Up @@ -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("_"),
},
);
}
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_lint/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_lint/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>);
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/hir/map/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down