Skip to content

Commit

Permalink
Rollup merge of #79019 - lcnr:generic-arg-validation, r=petrochenkov
Browse files Browse the repository at this point in the history
astconv: extract closures into a separate trait

Am currently looking into completely removing `check_generic_arg_count` and `create_substs_for_generic_args` was somewhat difficult to understand for me so I moved these closures into a trait.

This should not have changed the behavior of any of these methods
  • Loading branch information
jonas-schievink authored Nov 15, 2020
2 parents f66af28 + 894b1f7 commit 00396cb
Show file tree
Hide file tree
Showing 4 changed files with 292 additions and 178 deletions.
25 changes: 10 additions & 15 deletions compiler/rustc_typeck/src/astconv/generics.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::astconv::{
AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition,
AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
GenericArgCountResult, GenericArgPosition,
};
use crate::errors::AssocTypeBindingNotAllowed;
use rustc_ast::ast::ParamKindOrd;
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::{GenericArg, GenericArgs};
use rustc_hir::GenericArg;
use rustc_middle::ty::{
self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt,
};
Expand Down Expand Up @@ -90,20 +91,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// instantiate a `GenericArg`.
/// - `inferred_kind`: if no parameter was provided, and inference is enabled, then
/// creates a suitable inference variable.
pub fn create_substs_for_generic_args<'b>(
pub fn create_substs_for_generic_args<'a>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
parent_substs: &[subst::GenericArg<'tcx>],
has_self: bool,
self_ty: Option<Ty<'tcx>>,
arg_count: GenericArgCountResult,
args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs<'b>>, bool),
mut provided_kind: impl FnMut(&GenericParamDef, &GenericArg<'_>) -> subst::GenericArg<'tcx>,
mut inferred_kind: impl FnMut(
Option<&[subst::GenericArg<'tcx>]>,
&GenericParamDef,
bool,
) -> subst::GenericArg<'tcx>,
ctx: &mut impl CreateSubstsForGenericArgsCtxt<'a, 'tcx>,
) -> SubstsRef<'tcx> {
// Collect the segments of the path; we need to substitute arguments
// for parameters throughout the entire path (wherever there are
Expand Down Expand Up @@ -142,7 +137,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
substs.push(
self_ty
.map(|ty| ty.into())
.unwrap_or_else(|| inferred_kind(None, param, true)),
.unwrap_or_else(|| ctx.inferred_kind(None, param, true)),
);
params.next();
}
Expand All @@ -151,7 +146,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}

// Check whether this segment takes generic arguments and the user has provided any.
let (generic_args, infer_args) = args_for_def_id(def_id);
let (generic_args, infer_args) = ctx.args_for_def_id(def_id);

let mut args =
generic_args.iter().flat_map(|generic_args| generic_args.args.iter()).peekable();
Expand All @@ -173,7 +168,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
(GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _)
| (GenericArg::Type(_), GenericParamDefKind::Type { .. }, _)
| (GenericArg::Const(_), GenericParamDefKind::Const, _) => {
substs.push(provided_kind(param, arg));
substs.push(ctx.provided_kind(param, arg));
args.next();
params.next();
}
Expand All @@ -184,7 +179,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) => {
// We expected a lifetime argument, but got a type or const
// argument. That means we're inferring the lifetimes.
substs.push(inferred_kind(None, param, infer_args));
substs.push(ctx.inferred_kind(None, param, infer_args));
force_infer_lt = Some(arg);
params.next();
}
Expand Down Expand Up @@ -302,7 +297,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
(None, Some(&param)) => {
// If there are fewer arguments than parameters, it means
// we're inferring the remaining arguments.
substs.push(inferred_kind(Some(&substs), param, infer_args));
substs.push(ctx.inferred_kind(Some(&substs), param, infer_args));
params.next();
}

Expand Down
224 changes: 143 additions & 81 deletions compiler/rustc_typeck/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,23 @@ pub struct GenericArgCountResult {
pub correct: Result<(), GenericArgCountMismatch>,
}

pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> {
fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'a>>, bool);

fn provided_kind(
&mut self,
param: &ty::GenericParamDef,
arg: &GenericArg<'_>,
) -> subst::GenericArg<'tcx>;

fn inferred_kind(
&mut self,
substs: Option<&[subst::GenericArg<'tcx>]>,
param: &ty::GenericParamDef,
infer_args: bool,
) -> subst::GenericArg<'tcx>;
}

impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
pub fn ast_region_to_region(
&self,
Expand Down Expand Up @@ -321,81 +338,102 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);

let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self);
let default_needs_object_self = |param: &ty::GenericParamDef| {
if let GenericParamDefKind::Type { has_default, .. } = param.kind {
if is_object && has_default {
let default_ty = tcx.at(span).type_of(param.def_id);
let self_param = tcx.types.self_param;
if default_ty.walk().any(|arg| arg == self_param.into()) {
// There is no suitable inference default for a type parameter
// that references self, in an object type.
return true;

struct SubstsForAstPathCtxt<'a, 'tcx> {
astconv: &'a (dyn AstConv<'tcx> + 'a),
def_id: DefId,
generic_args: &'a GenericArgs<'a>,
span: Span,
missing_type_params: Vec<String>,
inferred_params: Vec<Span>,
infer_args: bool,
is_object: bool,
}

impl<'tcx, 'a> SubstsForAstPathCtxt<'tcx, 'a> {
fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool {
let tcx = self.astconv.tcx();
if let GenericParamDefKind::Type { has_default, .. } = param.kind {
if self.is_object && has_default {
let default_ty = tcx.at(self.span).type_of(param.def_id);
let self_param = tcx.types.self_param;
if default_ty.walk().any(|arg| arg == self_param.into()) {
// There is no suitable inference default for a type parameter
// that references self, in an object type.
return true;
}
}
}
}

false
};
false
}
}

let mut missing_type_params = vec![];
let mut inferred_params = vec![];
let substs = Self::create_substs_for_generic_args(
tcx,
def_id,
parent_substs,
self_ty.is_some(),
self_ty,
arg_count.clone(),
// Provide the generic args, and whether types should be inferred.
|did| {
if did == def_id {
(Some(generic_args), infer_args)
impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> {
fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'a>>, bool) {
if did == self.def_id {
(Some(self.generic_args), self.infer_args)
} else {
// The last component of this tuple is unimportant.
(None, false)
}
},
// Provide substitutions for parameters for which (valid) arguments have been provided.
|param, arg| match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
self.ast_region_to_region(&lt, Some(param)).into()
}
(GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
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.
}

fn provided_kind(
&mut self,
param: &ty::GenericParamDef,
arg: &GenericArg<'_>,
) -> subst::GenericArg<'tcx> {
let tcx = self.astconv.tcx();
match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
self.astconv.ast_region_to_region(&lt, Some(param)).into()
}
(&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
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 let (hir::TyKind::Infer, false) =
(&ty.kind, self.astconv.allow_ty_infer())
{
self.inferred_params.push(ty.span);
tcx.ty_error().into()
} else {
self.astconv.ast_ty_to_ty(&ty).into()
}
}
(GenericParamDefKind::Const, GenericArg::Const(ct)) => {
ty::Const::from_opt_const_arg_anon_const(
tcx,
ty::WithOptConstParam {
did: tcx.hir().local_def_id(ct.value.hir_id),
const_param_did: Some(param.def_id),
},
)
.into()
}
if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) {
inferred_params.push(ty.span);
tcx.ty_error().into()
} else {
self.ast_ty_to_ty(&ty).into()
}
}
(GenericParamDefKind::Const, GenericArg::Const(ct)) => {
ty::Const::from_opt_const_arg_anon_const(
tcx,
ty::WithOptConstParam {
did: tcx.hir().local_def_id(ct.value.hir_id),
const_param_did: Some(param.def_id),
},
)
.into()
_ => unreachable!(),
}
_ => unreachable!(),
},
// Provide substitutions for parameters for which arguments are inferred.
|substs, param, infer_args| {
}

fn inferred_kind(
&mut self,
substs: Option<&[subst::GenericArg<'tcx>]>,
param: &ty::GenericParamDef,
infer_args: bool,
) -> subst::GenericArg<'tcx> {
let tcx = self.astconv.tcx();
match param.kind {
GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(),
GenericParamDefKind::Type { has_default, .. } => {
Expand All @@ -407,48 +445,72 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// other type parameters may reference `Self` in their
// defaults. This will lead to an ICE if we are not
// careful!
if default_needs_object_self(param) {
missing_type_params.push(param.name.to_string());
if self.default_needs_object_self(param) {
self.missing_type_params.push(param.name.to_string());
tcx.ty_error().into()
} else {
// This is a default type parameter.
self.normalize_ty(
span,
tcx.at(span).type_of(param.def_id).subst_spanned(
tcx,
substs.unwrap(),
Some(span),
),
)
.into()
self.astconv
.normalize_ty(
self.span,
tcx.at(self.span).type_of(param.def_id).subst_spanned(
tcx,
substs.unwrap(),
Some(self.span),
),
)
.into()
}
} else if infer_args {
// No type parameters were provided, we can infer all.
let param =
if !default_needs_object_self(param) { Some(param) } else { None };
self.ty_infer(param, span).into()
let param = if !self.default_needs_object_self(param) {
Some(param)
} else {
None
};
self.astconv.ty_infer(param, self.span).into()
} else {
// We've already errored above about the mismatch.
tcx.ty_error().into()
}
}
GenericParamDefKind::Const => {
let ty = tcx.at(span).type_of(param.def_id);
let ty = tcx.at(self.span).type_of(param.def_id);
// FIXME(const_generics:defaults)
if infer_args {
// No const parameters were provided, we can infer all.
self.ct_infer(ty, Some(param), span).into()
self.astconv.ct_infer(ty, Some(param), self.span).into()
} else {
// We've already errored above about the mismatch.
tcx.const_error(ty).into()
}
}
}
},
}
}

let mut substs_ctx = SubstsForAstPathCtxt {
astconv: self,
def_id,
span,
generic_args,
missing_type_params: vec![],
inferred_params: vec![],
infer_args,
is_object,
};
let substs = Self::create_substs_for_generic_args(
tcx,
def_id,
parent_substs,
self_ty.is_some(),
self_ty,
arg_count.clone(),
&mut substs_ctx,
);

self.complain_about_missing_type_params(
missing_type_params,
substs_ctx.missing_type_params,
def_id,
span,
generic_args.args.is_empty(),
Expand Down
Loading

0 comments on commit 00396cb

Please sign in to comment.