Skip to content

Avoid follow-up errors if the number of generic parameters already doesn't match #125608

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

Merged
merged 9 commits into from
Jun 4, 2024
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
pub(crate) fn complain_about_missing_assoc_tys(
&self,
associated_types: FxIndexMap<Span, FxIndexSet<DefId>>,
potential_assoc_types: Vec<Span>,
potential_assoc_types: Vec<usize>,
trait_bounds: &[hir::PolyTraitRef<'_>],
) {
if associated_types.values().all(|v| v.is_empty()) {
Expand Down
28 changes: 9 additions & 19 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,11 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
if let Some(&param) = params.peek() {
if param.index == 0 {
if let GenericParamDefKind::Type { .. } = param.kind {
assert_eq!(&args[..], &[]);
args.push(
self_ty
.map(|ty| ty.into())
.unwrap_or_else(|| ctx.inferred_kind(None, param, true)),
.unwrap_or_else(|| ctx.inferred_kind(&args, param, true)),
);
params.next();
}
Expand Down Expand Up @@ -267,7 +268,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
// Since this is a const impl, we need to insert a host arg at the end of
// `PartialEq`'s generics, but this errors since `Rhs` isn't specified.
// To work around this, we infer all arguments until we reach the host param.
args.push(ctx.inferred_kind(Some(&args), param, infer_args));
args.push(ctx.inferred_kind(&args, param, infer_args));
params.next();
}
(GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _)
Expand All @@ -281,7 +282,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
GenericParamDefKind::Const { .. },
_,
) => {
args.push(ctx.provided_kind(param, arg));
args.push(ctx.provided_kind(&args, param, arg));
args_iter.next();
params.next();
}
Expand All @@ -292,7 +293,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
) => {
// We expected a lifetime argument, but got a type or const
// argument. That means we're inferring the lifetimes.
args.push(ctx.inferred_kind(None, param, infer_args));
args.push(ctx.inferred_kind(&args, param, infer_args));
force_infer_lt = Some((arg, param));
params.next();
}
Expand Down Expand Up @@ -388,7 +389,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
(None, Some(&param)) => {
// If there are fewer arguments than parameters, it means
// we're inferring the remaining arguments.
args.push(ctx.inferred_kind(Some(&args), param, infer_args));
args.push(ctx.inferred_kind(&args, param, infer_args));
params.next();
}

Expand Down Expand Up @@ -474,16 +475,9 @@ pub(crate) fn check_generic_arg_count(
return Ok(());
}

if provided_args > max_expected_args {
invalid_args.extend(
gen_args.args[max_expected_args..provided_args].iter().map(|arg| arg.span()),
);
};
invalid_args.extend(min_expected_args..provided_args);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this not give a backwards range (i.e. 2..1) if you have a fn foo<'a: 'a, 'b: 'b> and you call it foo::<'static>?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but that's the prev behaviour. I just merged the two loops


let gen_args_info = if provided_args > min_expected_args {
invalid_args.extend(
gen_args.args[min_expected_args..provided_args].iter().map(|arg| arg.span()),
);
let num_redundant_args = provided_args - min_expected_args;
GenericArgsInfo::ExcessLifetimes { num_redundant_args }
} else {
Expand Down Expand Up @@ -538,11 +532,7 @@ pub(crate) fn check_generic_arg_count(
let num_default_params = expected_max - expected_min;

let gen_args_info = if provided > expected_max {
invalid_args.extend(
gen_args.args[args_offset + expected_max..args_offset + provided]
.iter()
.map(|arg| arg.span()),
);
invalid_args.extend((expected_max..provided).map(|i| i + args_offset));
let num_redundant_args = provided - expected_max;

// Provide extra note if synthetic arguments like `impl Trait` are specified.
Expand Down Expand Up @@ -610,7 +600,7 @@ pub(crate) fn check_generic_arg_count(
explicit_late_bound,
correct: lifetimes_correct
.and(args_correct)
.map_err(|reported| GenericArgCountMismatch { reported: Some(reported), invalid_args }),
.map_err(|reported| GenericArgCountMismatch { reported, invalid_args }),
}
}

Expand Down
78 changes: 47 additions & 31 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,11 @@ pub(crate) enum GenericArgPosition {

/// A marker denoting that the generic arguments that were
/// provided did not match the respective generic parameters.
#[derive(Clone, Default, Debug)]
#[derive(Clone, Debug)]
pub struct GenericArgCountMismatch {
/// Indicates whether a fatal error was reported (`Some`), or just a lint (`None`).
pub reported: Option<ErrorGuaranteed>,
/// A list of spans of arguments provided that were not valid.
pub invalid_args: Vec<Span>,
pub reported: ErrorGuaranteed,
/// A list of indices of arguments provided that were not valid.
pub invalid_args: Vec<usize>,
}

/// Decorates the result of a generic argument count mismatch
Expand All @@ -240,13 +239,14 @@ pub trait GenericArgsLowerer<'a, 'tcx> {

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

fn inferred_kind(
&mut self,
args: Option<&[ty::GenericArg<'tcx>]>,
preceding_args: &[ty::GenericArg<'tcx>],
param: &ty::GenericParamDef,
infer_args: bool,
) -> ty::GenericArg<'tcx>;
Expand Down Expand Up @@ -404,10 +404,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty.is_some(),
);

if let Err(err) = &arg_count.correct
&& let Some(reported) = err.reported
{
self.set_tainted_by_errors(reported);
if let Err(err) = &arg_count.correct {
self.set_tainted_by_errors(err.reported);
}

// Skip processing if type has no generic parameters.
Expand All @@ -425,6 +423,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
span: Span,
inferred_params: Vec<Span>,
infer_args: bool,
incorrect_args: &'a Result<(), GenericArgCountMismatch>,
}

impl<'a, 'tcx> GenericArgsLowerer<'a, 'tcx> for GenericArgsCtxt<'a, 'tcx> {
Expand All @@ -439,11 +438,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

fn provided_kind(
&mut self,
preceding_args: &[ty::GenericArg<'tcx>],
param: &ty::GenericParamDef,
arg: &GenericArg<'tcx>,
) -> ty::GenericArg<'tcx> {
let tcx = self.lowerer.tcx();

if let Err(incorrect) = self.incorrect_args {
if incorrect.invalid_args.contains(&(param.index as usize)) {
return param.to_error(tcx, preceding_args);
}
}

let mut handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| {
if has_default {
tcx.check_optional_stability(
Expand Down Expand Up @@ -506,11 +512,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

fn inferred_kind(
&mut self,
args: Option<&[ty::GenericArg<'tcx>]>,
preceding_args: &[ty::GenericArg<'tcx>],
param: &ty::GenericParamDef,
infer_args: bool,
) -> ty::GenericArg<'tcx> {
let tcx = self.lowerer.tcx();

if let Err(incorrect) = self.incorrect_args {
if incorrect.invalid_args.contains(&(param.index as usize)) {
return param.to_error(tcx, preceding_args);
}
}
match param.kind {
GenericParamDefKind::Lifetime => self
.lowerer
Expand All @@ -529,15 +541,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
GenericParamDefKind::Type { has_default, .. } => {
if !infer_args && has_default {
// No type parameter provided, but a default exists.
let args = args.unwrap();
if args.iter().any(|arg| match arg.unpack() {
GenericArgKind::Type(ty) => ty.references_error(),
_ => false,
}) {
if let Some(prev) =
preceding_args.iter().find_map(|arg| match arg.unpack() {
GenericArgKind::Type(ty) => ty.error_reported().err(),
_ => None,
})
{
// Avoid ICE #86756 when type error recovery goes awry.
return Ty::new_misc_error(tcx).into();
return Ty::new_error(tcx, prev).into();
Comment on lines -532 to +551
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fishy ICE workaround, but I rather preserved it for now instead of looking into it

}
tcx.at(self.span).type_of(param.def_id).instantiate(tcx, args).into()
tcx.at(self.span)
.type_of(param.def_id)
.instantiate(tcx, preceding_args)
.into()
} else if infer_args {
self.lowerer.ty_infer(Some(param), self.span).into()
} else {
Expand All @@ -557,7 +573,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// FIXME(effects) see if we should special case effect params here
if !infer_args && has_default {
tcx.const_param_default(param.def_id)
.instantiate(tcx, args.unwrap())
.instantiate(tcx, preceding_args)
.into()
} else {
if infer_args {
Expand All @@ -571,6 +587,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}
}
if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness
&& generics.has_self
&& !tcx.has_attr(def_id, sym::const_trait)
{
let reported = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
span,
modifier: constness.as_str(),
});
self.set_tainted_by_errors(reported);
arg_count.correct = Err(GenericArgCountMismatch { reported, invalid_args: vec![] });
}

let mut args_ctx = GenericArgsCtxt {
lowerer: self,
Expand All @@ -579,19 +606,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
generic_args: segment.args(),
inferred_params: vec![],
infer_args: segment.infer_args,
incorrect_args: &arg_count.correct,
};
if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness
&& generics.has_self
&& !tcx.has_attr(def_id, sym::const_trait)
{
let e = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
span,
modifier: constness.as_str(),
});
self.set_tainted_by_errors(e);
arg_count.correct =
Err(GenericArgCountMismatch { reported: Some(e), invalid_args: vec![] });
}
let args = lower_generic_args(
tcx,
def_id,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir_analysis/src/impl_wf_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ fn enforce_impl_params_are_constrained(
let impl_predicates = tcx.predicates_of(impl_def_id);
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity);

impl_trait_ref.error_reported()?;

let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref);
cgp::identify_constrained_generic_params(
tcx,
Expand Down
32 changes: 18 additions & 14 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1118,7 +1118,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// to add defaults. If the user provided *too many* types, that's
// a problem.

let mut infer_args_for_err = FxHashSet::default();
let mut infer_args_for_err = None;

let mut explicit_late_bound = ExplicitLateBound::No;
for &GenericPathSegment(def_id, index) in &generic_segments {
Expand All @@ -1136,9 +1136,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
explicit_late_bound = ExplicitLateBound::Yes;
}

if let Err(GenericArgCountMismatch { reported: Some(e), .. }) = arg_count.correct {
infer_args_for_err.insert(index);
self.set_tainted_by_errors(e); // See issue #53251.
if let Err(GenericArgCountMismatch { reported, .. }) = arg_count.correct {
infer_args_for_err
.get_or_insert_with(|| (reported, FxHashSet::default()))
.1
.insert(index);
self.set_tainted_by_errors(reported); // See issue #53251.
}
}

Expand Down Expand Up @@ -1232,15 +1235,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let def_id = res.def_id();

let arg_count = GenericArgCountResult {
explicit_late_bound,
correct: if infer_args_for_err.is_empty() {
Ok(())
} else {
Err(GenericArgCountMismatch::default())
},
let (correct, infer_args_for_err) = match infer_args_for_err {
Some((reported, args)) => {
(Err(GenericArgCountMismatch { reported, invalid_args: vec![] }), args)
}
None => (Ok(()), Default::default()),
};

let arg_count = GenericArgCountResult { explicit_late_bound, correct };

struct CtorGenericArgsCtxt<'a, 'tcx> {
fcx: &'a FnCtxt<'a, 'tcx>,
span: Span,
Expand Down Expand Up @@ -1272,6 +1275,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

fn provided_kind(
&mut self,
_preceding_args: &[ty::GenericArg<'tcx>],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could actually allow generic const generics now here, but there's probably other work required elsewhere to support it properly

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah basically nothing is set up for that at all lol

param: &ty::GenericParamDef,
arg: &GenericArg<'tcx>,
) -> ty::GenericArg<'tcx> {
Expand Down Expand Up @@ -1314,7 +1318,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

fn inferred_kind(
&mut self,
args: Option<&[ty::GenericArg<'tcx>]>,
preceding_args: &[ty::GenericArg<'tcx>],
param: &ty::GenericParamDef,
infer_args: bool,
) -> ty::GenericArg<'tcx> {
Expand All @@ -1328,7 +1332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If we have a default, then it doesn't matter that we're not
// inferring the type arguments: we provide the default where any
// is missing.
tcx.type_of(param.def_id).instantiate(tcx, args.unwrap()).into()
tcx.type_of(param.def_id).instantiate(tcx, preceding_args).into()
} else {
// If no type arguments were provided, we have to infer them.
// This case also occurs as a result of some malformed input, e.g.
Expand All @@ -1353,7 +1357,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else if !infer_args {
return tcx
.const_param_default(param.def_id)
.instantiate(tcx, args.unwrap())
.instantiate(tcx, preceding_args)
.into();
}
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_hir_typeck/src/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {

fn provided_kind(
&mut self,
_preceding_args: &[ty::GenericArg<'tcx>],
param: &ty::GenericParamDef,
arg: &GenericArg<'tcx>,
) -> ty::GenericArg<'tcx> {
Expand Down Expand Up @@ -419,7 +420,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {

fn inferred_kind(
&mut self,
_args: Option<&[ty::GenericArg<'tcx>]>,
_preceding_args: &[ty::GenericArg<'tcx>],
param: &ty::GenericParamDef,
_infer_args: bool,
) -> ty::GenericArg<'tcx> {
Expand Down
20 changes: 0 additions & 20 deletions tests/crashes/121134.rs

This file was deleted.

Loading
Loading