summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /compiler/rustc_hir_analysis/src
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz
rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/bounds.rs66
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs107
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/generics.rs24
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/lint.rs27
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs91
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/object_safety.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs28
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs101
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs342
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/entry.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs339
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs295
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs47
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs43
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs79
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs89
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs33
-rw-r--r--compiler/rustc_hir_analysis/src/constrained_generic_params.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs186
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs66
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs28
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs129
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs2
30 files changed, 1344 insertions, 829 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index 21611e9c5..3e700f2da 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -8,6 +8,7 @@ use rustc_middle::ty::{self as ty, Ty, TypeVisitableExt};
use rustc_span::symbol::Ident;
use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::traits;
+use smallvec::SmallVec;
use crate::astconv::{
AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter,
@@ -28,15 +29,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let tcx = self.tcx();
// Try to find an unbound in bounds.
- let mut unbound = None;
+ let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
for ab in ast_bounds {
if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
- if unbound.is_none() {
- unbound = Some(&ptr.trait_ref);
- } else {
- tcx.sess.emit_err(errors::MultipleRelaxedDefaultBounds { span });
- }
+ unbounds.push(ptr)
}
}
};
@@ -51,33 +48,41 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
}
}
+ if unbounds.len() > 1 {
+ tcx.sess.emit_err(errors::MultipleRelaxedDefaultBounds {
+ spans: unbounds.iter().map(|ptr| ptr.span).collect(),
+ });
+ }
+
let sized_def_id = tcx.lang_items().sized_trait();
- match (&sized_def_id, unbound) {
- (Some(sized_def_id), Some(tpb))
- if tpb.path.res == Res::Def(DefKind::Trait, *sized_def_id) =>
- {
- // There was in fact a `?Sized` bound, return without doing anything
- return;
- }
- (_, Some(_)) => {
- // There was a `?Trait` bound, but it was not `?Sized`; warn.
- tcx.sess.span_warn(
- span,
- "default bound relaxed for a type parameter, but \
- this does nothing because the given bound is not \
- a default; only `?Sized` is supported",
- );
- // Otherwise, add implicitly sized if `Sized` is available.
- }
- _ => {
- // There was no `?Sized` bound; add implicitly sized if `Sized` is available.
+
+ let mut seen_sized_unbound = false;
+ for unbound in unbounds {
+ if let Some(sized_def_id) = sized_def_id {
+ if unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) {
+ seen_sized_unbound = true;
+ continue;
+ }
}
+ // There was a `?Trait` bound, but it was not `?Sized`; warn.
+ tcx.sess.span_warn(
+ unbound.span,
+ "relaxing a default bound only does something for `?Sized`; \
+ all other traits are not bound by default",
+ );
}
+
+ // If the above loop finished there was no `?Sized` bound; add implicitly sized if `Sized` is available.
if sized_def_id.is_none() {
// No lang item for `Sized`, so we can't add it as a bound.
return;
}
- bounds.push_sized(tcx, self_ty, span);
+ if seen_sized_unbound {
+ // There was in fact a `?Sized` bound, return without doing anything
+ } else {
+ // There was no `?Sized` bound; add implicitly sized if `Sized` is available.
+ bounds.push_sized(tcx, self_ty, span);
+ }
}
/// This helper takes a *converted* parameter type (`param_ty`)
@@ -284,6 +289,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
self.one_bound_for_assoc_type(
|| traits::supertraits(tcx, trait_ref),
trait_ref.skip_binder().print_only_trait_name(),
+ None,
binding.item_name,
path_span,
match binding.kind {
@@ -447,7 +453,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
debug!(?args_trait_ref_and_assoc_item);
- tcx.mk_alias_ty(assoc_item.def_id, args_trait_ref_and_assoc_item)
+ ty::AliasTy::new(tcx, assoc_item.def_id, args_trait_ref_and_assoc_item)
})
};
@@ -517,8 +523,10 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
);
if let DefKind::AssocConst = def_kind
- && let Some(t) = term.ty() && (t.is_enum() || t.references_error())
- && tcx.features().associated_const_equality {
+ && let Some(t) = term.ty()
+ && (t.is_enum() || t.references_error())
+ && tcx.features().associated_const_equality
+ {
err.span_suggestion(
binding.span,
"if equating a const, try wrapping with braces",
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index ed4dde419..32be7e083 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -3,17 +3,18 @@ use crate::errors::{
AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
ParenthesizedFnTraitExpansion,
};
+use crate::traits::error_reporting::report_object_safety_error;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::traits::FulfillmentError;
-use rustc_middle::ty::TyCtxt;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt};
use rustc_session::parse::feature_err;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{sym, Ident};
use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_trait_selection::traits::object_safety_violations_for_assoc_item;
use std::collections::BTreeSet;
@@ -102,6 +103,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&self,
all_candidates: impl Fn() -> I,
ty_param_name: &str,
+ ty_param_def_id: Option<LocalDefId>,
assoc_name: Ident,
span: Span,
) -> ErrorGuaranteed
@@ -190,13 +192,61 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
})
.collect::<Vec<_>>()[..]
{
+ let trait_name = self.tcx().def_path_str(*best_trait);
+ let an = if suggested_name != assoc_name.name { "a similarly named" } else { "an" };
err.span_label(
assoc_name.span,
format!(
- "there is a similarly named associated type `{suggested_name}` in the trait `{}`",
- self.tcx().def_path_str(*best_trait)
+ "there is {an} associated type `{suggested_name}` in the \
+ trait `{trait_name}`",
),
);
+ let hir = self.tcx().hir();
+ if let Some(def_id) = ty_param_def_id
+ && let parent = hir.get_parent_item(hir.local_def_id_to_hir_id(def_id))
+ && let Some(generics) = hir.get_generics(parent.def_id)
+ {
+ if generics.bounds_for_param(def_id)
+ .flat_map(|pred| pred.bounds.iter())
+ .any(|b| match b {
+ hir::GenericBound::Trait(t, ..) => {
+ t.trait_ref.trait_def_id().as_ref() == Some(best_trait)
+ }
+ _ => false,
+ })
+ {
+ // The type param already has a bound for `trait_name`, we just need to
+ // change the associated type.
+ err.span_suggestion_verbose(
+ assoc_name.span,
+ format!(
+ "change the associated type name to use `{suggested_name}` from \
+ `{trait_name}`",
+ ),
+ suggested_name.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ } else if suggest_constraining_type_param(
+ self.tcx(),
+ generics,
+ &mut err,
+ &ty_param_name,
+ &trait_name,
+ None,
+ None,
+ )
+ && suggested_name != assoc_name.name
+ {
+ // We suggested constraining a type parameter, but the associated type on it
+ // was also not an exact match, so we also suggest changing it.
+ err.span_suggestion_verbose(
+ assoc_name.span,
+ "and also change the associated type name",
+ suggested_name.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
return err.emit();
}
}
@@ -389,7 +439,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);
let quiet_projection_ty =
- tcx.mk_alias_ty(projection_ty.def_id, args_with_infer_self);
+ ty::AliasTy::new(tcx, projection_ty.def_id, args_with_infer_self);
let term = pred.skip_binder().term;
@@ -472,24 +522,33 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
(span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect())
})
.collect();
- let mut names = vec![];
+ let mut names: FxHashMap<String, Vec<Symbol>> = Default::default();
+ let mut names_len = 0;
// Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
// `issue-22560.rs`.
let mut trait_bound_spans: Vec<Span> = vec![];
+ let mut object_safety_violations = false;
for (span, items) in &associated_types {
if !items.is_empty() {
trait_bound_spans.push(*span);
}
for assoc_item in items {
let trait_def_id = assoc_item.container_id(tcx);
- names.push(format!(
- "`{}` (from trait `{}`)",
- assoc_item.name,
- tcx.def_path_str(trait_def_id),
- ));
+ names.entry(tcx.def_path_str(trait_def_id)).or_default().push(assoc_item.name);
+ names_len += 1;
+
+ let violations =
+ object_safety_violations_for_assoc_item(tcx, trait_def_id, *assoc_item);
+ if !violations.is_empty() {
+ report_object_safety_error(tcx, *span, trait_def_id, &violations).emit();
+ object_safety_violations = true;
+ }
}
}
+ if object_safety_violations {
+ return;
+ }
if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
match bound.trait_ref.path.segments {
// FIXME: `trait_ref.path.span` can point to a full path with multiple
@@ -525,15 +584,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
_ => {}
}
}
+
+ let mut names = names
+ .into_iter()
+ .map(|(trait_, mut assocs)| {
+ assocs.sort();
+ format!(
+ "{} in `{trait_}`",
+ match &assocs[..] {
+ [] => String::new(),
+ [only] => format!("`{only}`"),
+ [assocs @ .., last] => format!(
+ "{} and `{last}`",
+ assocs.iter().map(|a| format!("`{a}`")).collect::<Vec<_>>().join(", ")
+ ),
+ }
+ )
+ })
+ .collect::<Vec<String>>();
names.sort();
+ let names = names.join(", ");
+
trait_bound_spans.sort();
let mut err = struct_span_err!(
tcx.sess,
trait_bound_spans,
E0191,
"the value of the associated type{} {} must be specified",
- pluralize!(names.len()),
- names.join(", "),
+ pluralize!(names_len),
+ names,
);
let mut suggestions = vec![];
let mut types_count = 0;
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index e3621ef93..d29a27ece 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -429,12 +429,22 @@ pub(crate) fn check_generic_arg_count(
.filter(|param| matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. }))
.count();
let named_type_param_count = param_counts.types - has_self as usize - synth_type_param_count;
+ let synth_const_param_count = gen_params
+ .params
+ .iter()
+ .filter(|param| {
+ matches!(param.kind, ty::GenericParamDefKind::Const { is_host_effect: true, .. })
+ })
+ .count();
+ let named_const_param_count = param_counts.consts - synth_const_param_count;
let infer_lifetimes =
(gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
- if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() {
- prohibit_assoc_ty_binding(tcx, b.span, None);
- }
+ if gen_pos != GenericArgPosition::Type
+ && let Some(b) = gen_args.bindings.first()
+ {
+ prohibit_assoc_ty_binding(tcx, b.span, None);
+ }
let explicit_late_bound =
prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos);
@@ -571,11 +581,13 @@ pub(crate) fn check_generic_arg_count(
debug!(?expected_min);
debug!(arg_counts.lifetimes=?gen_args.num_lifetime_params());
+ let provided = gen_args.num_generic_params();
+
check_types_and_consts(
expected_min,
- param_counts.consts + named_type_param_count,
- param_counts.consts + named_type_param_count + synth_type_param_count,
- gen_args.num_generic_params(),
+ named_const_param_count + named_type_param_count,
+ named_const_param_count + named_type_param_count + synth_type_param_count,
+ provided,
param_counts.lifetimes + has_self as usize,
gen_args.num_lifetime_params(),
)
diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs
index 1bd1270be..bc57bbcca 100644
--- a/compiler/rustc_hir_analysis/src/astconv/lint.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs
@@ -18,18 +18,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if let hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Impl(hir::Impl {
- self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, ..
+ self_ty: impl_self_ty,
+ of_trait: Some(of_trait_ref),
+ generics,
+ ..
}),
..
- }) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
+ }) = tcx.hir().get_by_def_id(parent_id)
+ && self_ty.hir_id == impl_self_ty.hir_id
{
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
return;
}
let of_trait_span = of_trait_ref.path.span;
// make sure that we are not calling unwrap to abort during the compilation
- let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; };
- let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; };
+ let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
+ return;
+ };
+ let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else {
+ return;
+ };
// check if the trait has generics, to make a correct suggestion
let param_name = generics.params.next_type_param_name(None);
@@ -39,13 +47,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
(generics.span, format!("<{param_name}: {impl_trait_name}>"))
};
diag.multipart_suggestion(
- format!("alternatively use a blanket \
+ format!(
+ "alternatively use a blanket \
implementation to implement `{of_trait_name}` for \
- all types that also implement `{impl_trait_name}`"),
- vec![
- (self_ty.span, param_name),
- add_generic_sugg,
- ],
+ all types that also implement `{impl_trait_name}`"
+ ),
+ vec![(self_ty.span, param_name), add_generic_sugg],
Applicability::MaybeIncorrect,
);
}
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 56b1fd369..2fcb45ef8 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -36,7 +36,7 @@ use rustc_middle::ty::{
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::{sym, Span, DUMMY_SP};
+use rustc_span::{sym, BytePos, Span, DUMMY_SP};
use rustc_target::spec::abi;
use rustc_trait_selection::traits::wf::object_region_bounds;
use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCtxt};
@@ -567,9 +567,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);
if let ty::BoundConstness::ConstIfConst = constness
- && generics.has_self && !tcx.has_attr(def_id, sym::const_trait)
+ && generics.has_self
+ && !tcx.has_attr(def_id, sym::const_trait)
{
- tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span } );
+ tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span });
}
(args, arg_count)
@@ -915,7 +916,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Type aliases defined in crates that have the
// feature `lazy_type_alias` enabled get encoded as a type alias that normalization will
// then actually instantiate the where bounds of.
- let alias_ty = tcx.mk_alias_ty(did, args);
+ let alias_ty = ty::AliasTy::new(tcx, did, args);
Ty::new_alias(tcx, ty::Weak, alias_ty)
} else {
tcx.at(span).type_of(did).instantiate(tcx, args)
@@ -1017,7 +1018,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
err.span_suggestions(
span,
- "use the fully-qualified path",
+ "use fully-qualified syntax",
suggestions,
Applicability::MachineApplicable,
);
@@ -1061,6 +1062,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
)
},
param_name,
+ Some(ty_param_def_id),
assoc_name,
span,
None,
@@ -1074,6 +1076,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&self,
all_candidates: impl Fn() -> I,
ty_param_name: impl Display,
+ ty_param_def_id: Option<LocalDefId>,
assoc_name: Ident,
span: Span,
is_equality: Option<ty::Term<'tcx>>,
@@ -1088,13 +1091,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Const, assoc_name)
});
- let (bound, next_cand) = match (matching_candidates.next(), const_candidates.next()) {
+ let (mut bound, mut next_cand) = match (matching_candidates.next(), const_candidates.next())
+ {
(Some(bound), _) => (bound, matching_candidates.next()),
(None, Some(bound)) => (bound, const_candidates.next()),
(None, None) => {
let reported = self.complain_about_assoc_type_not_found(
all_candidates,
&ty_param_name.to_string(),
+ ty_param_def_id,
assoc_name,
span,
);
@@ -1103,6 +1108,37 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
debug!(?bound);
+ // look for a candidate that is not the same as our first bound, disregarding
+ // whether the bound is const.
+ while let Some(mut bound2) = next_cand {
+ debug!(?bound2);
+ let tcx = self.tcx();
+ if bound2.bound_vars() != bound.bound_vars() {
+ break;
+ }
+
+ let generics = tcx.generics_of(bound.def_id());
+ let Some(host_index) = generics.host_effect_index else { break };
+
+ // always return the bound that contains the host param.
+ if let ty::ConstKind::Param(_) = bound2.skip_binder().args.const_at(host_index).kind() {
+ (bound, bound2) = (bound2, bound);
+ }
+
+ let unconsted_args = bound
+ .skip_binder()
+ .args
+ .iter()
+ .enumerate()
+ .map(|(n, arg)| if host_index == n { tcx.consts.true_.into() } else { arg });
+
+ if unconsted_args.eq(bound2.skip_binder().args.iter()) {
+ next_cand = matching_candidates.next().or_else(|| const_candidates.next());
+ } else {
+ break;
+ }
+ }
+
if let Some(bound2) = next_cand {
debug!(?bound2);
@@ -1142,30 +1178,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.span_label(
bound_span,
format!(
- "ambiguous `{}` from `{}`",
- assoc_name,
+ "ambiguous `{assoc_name}` from `{}`",
bound.print_only_trait_path(),
),
);
if let Some(constraint) = &is_equality {
where_bounds.push(format!(
- " T: {trait}::{assoc} = {constraint}",
+ " T: {trait}::{assoc_name} = {constraint}",
trait=bound.print_only_trait_path(),
- assoc=assoc_name,
- constraint=constraint,
));
} else {
err.span_suggestion_verbose(
span.with_hi(assoc_name.span.lo()),
- "use fully qualified syntax to disambiguate",
- format!("<{} as {}>::", ty_param_name, bound.print_only_trait_path()),
+ "use fully-qualified syntax to disambiguate",
+ format!("<{ty_param_name} as {}>::", bound.print_only_trait_path()),
Applicability::MaybeIncorrect,
);
}
} else {
err.note(format!(
- "associated type `{}` could derive from `{}`",
- ty_param_name,
+ "associated type `{ty_param_name}` could derive from `{}`",
bound.print_only_trait_path(),
));
}
@@ -1173,8 +1205,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if !where_bounds.is_empty() {
err.help(format!(
"consider introducing a new type parameter `T` and adding `where` constraints:\
- \n where\n T: {},\n{}",
- ty_param_name,
+ \n where\n T: {ty_param_name},\n{}",
where_bounds.join(",\n"),
));
}
@@ -1275,8 +1306,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
return;
};
// Get the span of the generics args *including* the leading `::`.
- let args_span =
- assoc_segment.ident.span.shrink_to_hi().to(args.span_ext);
+ // We do so by stretching args.span_ext to the left by 2. Earlier
+ // it was done based on the end of assoc segment but that sometimes
+ // led to impossible spans and caused issues like #116473
+ let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
if tcx.generics_of(adt_def.did()).count() == 0 {
// FIXME(estebank): we could also verify that the arguments being
// work for the `enum`, instead of just looking if it takes *any*.
@@ -1394,6 +1427,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
)
},
kw::SelfUpper,
+ None,
assoc_ident,
span,
None,
@@ -1684,7 +1718,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.chain(args.into_iter().skip(parent_args.len())),
);
- let ty = Ty::new_alias(tcx, ty::Inherent, tcx.mk_alias_ty(assoc_item, args));
+ let ty = Ty::new_alias(tcx, ty::Inherent, ty::AliasTy::new(tcx, assoc_item, args));
return Ok(Some((ty, assoc_item)));
}
@@ -1917,9 +1951,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
} else {
Some((
match segment.res {
- Res::PrimTy(ty) => format!("{} `{}`", segment.res.descr(), ty.name()),
+ Res::PrimTy(ty) => {
+ format!("{} `{}`", segment.res.descr(), ty.name())
+ }
Res::Def(_, def_id)
- if let Some(name) = self.tcx().opt_item_name(def_id) => {
+ if let Some(name) = self.tcx().opt_item_name(def_id) =>
+ {
format!("{} `{name}`", segment.res.descr())
}
Res::Err => "this type".to_string(),
@@ -2249,7 +2286,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.note(msg);
}
for segment in path.segments {
- if let Some(args) = segment.args && segment.ident.name == kw::SelfUpper {
+ if let Some(args) = segment.args
+ && segment.ident.name == kw::SelfUpper
+ {
if generics == 0 {
// FIXME(estebank): we could also verify that the arguments being
// work for the `enum`, instead of just looking if it takes *any*.
@@ -2631,7 +2670,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.iter()
.enumerate()
.map(|(i, a)| {
- if let hir::TyKind::Infer = a.kind && !self.allow_ty_infer() {
+ if let hir::TyKind::Infer = a.kind
+ && !self.allow_ty_infer()
+ {
if let Some(suggested_ty) =
self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
{
@@ -2660,7 +2701,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.ast_ty_to_ty(output)
}
}
- hir::FnRetTy::DefaultReturn(..) => Ty::new_unit(tcx,),
+ hir::FnRetTy::DefaultReturn(..) => Ty::new_unit(tcx),
};
debug!(?output_ty);
diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
index 30c2ab8f5..00ff3f836 100644
--- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
@@ -380,7 +380,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
span,
E0228,
"the lifetime bound for this object type cannot be deduced \
- from context; please supply an explicit bound"
+ from context; please supply an explicit bound"
);
let e = if borrowed {
// We will have already emitted an error E0106 complaining about a
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index 1d9ae2b9c..b6688e0ce 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -44,6 +44,34 @@ impl<'tcx> Bounds<'tcx> {
span: Span,
polarity: ty::ImplPolarity,
) {
+ self.push_trait_bound_inner(tcx, trait_ref, span, polarity);
+
+ // push a non-const (`host = true`) version of the bound if it is `~const`.
+ if tcx.features().effects
+ && let Some(host_effect_idx) = tcx.generics_of(trait_ref.def_id()).host_effect_index
+ && trait_ref.skip_binder().args.const_at(host_effect_idx) != tcx.consts.true_
+ {
+ let generics = tcx.generics_of(trait_ref.def_id());
+ let Some(host_index) = generics.host_effect_index else { return };
+ let trait_ref = trait_ref.map_bound(|mut trait_ref| {
+ trait_ref.args =
+ tcx.mk_args_from_iter(trait_ref.args.iter().enumerate().map(|(n, arg)| {
+ if host_index == n { tcx.consts.true_.into() } else { arg }
+ }));
+ trait_ref
+ });
+
+ self.push_trait_bound_inner(tcx, trait_ref, span, polarity);
+ }
+ }
+
+ fn push_trait_bound_inner(
+ &mut self,
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ span: Span,
+ polarity: ty::ImplPolarity,
+ ) {
self.clauses.push((
trait_ref
.map_bound(|trait_ref| {
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 44e1bdb83..e61ca232d 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -128,7 +128,11 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
let param_env = tcx.param_env(item_def_id);
for field in &def.non_enum_variant().fields {
- let field_ty = tcx.normalize_erasing_regions(param_env, field.ty(tcx, args));
+ let Ok(field_ty) = tcx.try_normalize_erasing_regions(param_env, field.ty(tcx, args))
+ else {
+ tcx.sess.delay_span_bug(span, "could not normalize field type");
+ continue;
+ };
if !allowed_union_field(field_ty, tcx, param_env) {
let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) {
@@ -291,7 +295,7 @@ fn check_opaque_meets_bounds<'tcx>(
let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
- // `ReErased` regions appear in the "parent_args" of closures/generators.
+ // `ReErased` regions appear in the "parent_args" of closures/coroutines.
// We're ignoring them here and replacing them with fresh region variables.
// See tests in ui/type-alias-impl-trait/closure_{parent_args,wf_outlives}.rs.
//
@@ -327,7 +331,7 @@ fn check_opaque_meets_bounds<'tcx>(
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let guar = infcx.err_ctxt().report_fulfillment_errors(&errors);
+ let guar = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(guar);
}
match origin {
@@ -481,8 +485,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
fn_maybe_err(tcx, assoc_item.ident(tcx).span, abi);
}
ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
- let trait_args =
- GenericArgs::identity_for_item(tcx, id.owner_id);
+ let trait_args = GenericArgs::identity_for_item(tcx, id.owner_id);
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
tcx,
assoc_item,
@@ -502,7 +505,8 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
}
DefKind::OpaqueTy => {
let origin = tcx.opaque_type_origin(id.owner_id.def_id);
- if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin
+ if let hir::OpaqueTyOrigin::FnReturn(fn_def_id)
+ | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin
&& let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id)
&& let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
{
@@ -589,7 +593,9 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
}
DefKind::GlobalAsm => {
let it = tcx.hir().item(id);
- let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) };
+ let hir::ItemKind::GlobalAsm(asm) = it.kind else {
+ span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it)
+ };
InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.owner_id.def_id);
}
_ => {}
@@ -783,21 +789,21 @@ fn check_impl_items_against_trait<'tcx>(
let (msg, feature) = if tcx.asyncness(def_id).is_async() {
(
format!("async {descr} in trait cannot be specialized"),
- sym::async_fn_in_trait,
+ "async functions in traits",
)
} else {
(
format!(
"{descr} with return-position `impl Trait` in trait cannot be specialized"
),
- sym::return_position_impl_trait_in_trait,
+ "return position `impl Trait` in traits",
)
};
tcx.sess
.struct_span_err(tcx.def_span(def_id), msg)
.note(format!(
"specialization behaves in inconsistent and \
- surprising ways with `#![feature({feature})]`, \
+ surprising ways with {feature}, \
and for now is disallowed"
))
.emit();
@@ -873,10 +879,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok
ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct<T>([T; N]) through, let monomorphization catch errors
ty::Array(t, _clen)
- if matches!(
- t.kind(),
- ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)
- ) =>
+ if matches!(t.kind(), ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)) =>
{ /* struct([f32; 4]) is ok */ }
_ => {
struct_span_err!(
@@ -899,17 +902,17 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
for attr in tcx.get_attrs(def.did(), sym::repr) {
for r in attr::parse_repr_attr(&tcx.sess, attr) {
if let attr::ReprPacked(pack) = r
- && let Some(repr_pack) = repr.pack
- && pack as u64 != repr_pack.bytes()
- {
- struct_span_err!(
- tcx.sess,
- sp,
- E0634,
- "type has conflicting packed representation hints"
- )
- .emit();
- }
+ && let Some(repr_pack) = repr.pack
+ && pack as u64 != repr_pack.bytes()
+ {
+ struct_span_err!(
+ tcx.sess,
+ sp,
+ E0634,
+ "type has conflicting packed representation hints"
+ )
+ .emit();
+ }
}
}
if repr.align.is_some() {
@@ -1174,7 +1177,8 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
let (span, display_discr) = match var.discr {
ty::VariantDiscr::Explicit(discr_def_id) => {
// In the case the discriminant is both a duplicate and overflowed, let the user know
- if let hir::Node::AnonConst(expr) = tcx.hir().get_by_def_id(discr_def_id.expect_local())
+ if let hir::Node::AnonConst(expr) =
+ tcx.hir().get_by_def_id(discr_def_id.expect_local())
&& let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
&& *lit_value != dis.val
@@ -1303,15 +1307,9 @@ pub(super) fn check_type_params_are_used<'tcx>(
&& let ty::GenericParamDefKind::Type { .. } = param.kind
{
let span = tcx.def_span(param.def_id);
- struct_span_err!(
- tcx.sess,
- span,
- E0091,
- "type parameter `{}` is unused",
- param.name,
- )
- .span_label(span, "unused type parameter")
- .emit();
+ struct_span_err!(tcx.sess, span, E0091, "type parameter `{}` is unused", param.name,)
+ .span_label(span, "unused type parameter")
+ .emit();
}
}
}
@@ -1400,7 +1398,7 @@ fn opaque_type_cycle_error(
self.opaques.push(def);
ControlFlow::Continue(())
}
- ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => {
+ ty::Closure(def_id, ..) | ty::Coroutine(def_id, ..) => {
self.closures.push(def_id);
t.super_visit_with(self)
}
@@ -1430,7 +1428,10 @@ fn opaque_type_cycle_error(
let mut label_match = |ty: Ty<'_>, span| {
for arg in ty.walk() {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
- && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: captured_def_id, .. }) = *ty.kind()
+ && let ty::Alias(
+ ty::Opaque,
+ ty::AliasTy { def_id: captured_def_id, .. },
+ ) = *ty.kind()
&& captured_def_id == opaque_def_id.to_def_id()
{
err.span_label(
@@ -1449,11 +1450,11 @@ fn opaque_type_cycle_error(
{
label_match(capture.place.ty(), capture.get_path_span(tcx));
}
- // Label any generator locals that capture the opaque
- if let DefKind::Generator = tcx.def_kind(closure_def_id)
- && let Some(generator_layout) = tcx.mir_generator_witnesses(closure_def_id)
+ // Label any coroutine locals that capture the opaque
+ if let DefKind::Coroutine = tcx.def_kind(closure_def_id)
+ && let Some(coroutine_layout) = tcx.mir_coroutine_witnesses(closure_def_id)
{
- for interior_ty in &generator_layout.field_tys {
+ for interior_ty in &coroutine_layout.field_tys {
label_match(interior_ty.ty, interior_ty.source_info.span);
}
}
@@ -1467,14 +1468,14 @@ fn opaque_type_cycle_error(
err.emit()
}
-pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Generator));
+pub(super) fn check_coroutine_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+ debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Coroutine));
let typeck = tcx.typeck(def_id);
let param_env = tcx.param_env(def_id);
- let generator_interior_predicates = &typeck.generator_interior_predicates[&def_id];
- debug!(?generator_interior_predicates);
+ let coroutine_interior_predicates = &typeck.coroutine_interior_predicates[&def_id];
+ debug!(?coroutine_interior_predicates);
let infcx = tcx
.infer_ctxt()
@@ -1486,15 +1487,15 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
.build();
let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(&infcx);
- for (predicate, cause) in generator_interior_predicates {
+ for (predicate, cause) in coroutine_interior_predicates {
let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate);
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
}
if (tcx.features().unsized_locals || tcx.features().unsized_fn_params)
- && let Some(generator) = tcx.mir_generator_witnesses(def_id)
+ && let Some(coroutine) = tcx.mir_coroutine_witnesses(def_id)
{
- for field_ty in generator.field_tys.iter() {
+ for field_ty in coroutine.field_tys.iter() {
fulfillment_cx.register_bound(
&infcx,
param_env,
@@ -1503,7 +1504,7 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
ObligationCause::new(
field_ty.source_info.span,
def_id,
- ObligationCauseCode::SizedGeneratorInterior(def_id),
+ ObligationCauseCode::SizedCoroutineInterior(def_id),
),
);
}
@@ -1512,6 +1513,6 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let errors = fulfillment_cx.select_all_or_error(&infcx);
debug!(?errors);
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors);
+ infcx.err_ctxt().report_fulfillment_errors(errors);
}
}
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index d081b0e35..857515f97 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -16,6 +16,7 @@ use rustc_infer::traits::util;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::util::ExplicitSelf;
+use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::{
self, GenericArgs, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
};
@@ -322,7 +323,7 @@ fn compare_method_predicate_entailment<'tcx>(
// FIXME(-Ztrait-solver=next): Not needed when the hack below is removed.
let errors = ocx.select_where_possible();
if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(reported);
}
@@ -393,7 +394,7 @@ fn compare_method_predicate_entailment<'tcx>(
});
}
CheckImpliedWfMode::Skip => {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(reported);
}
}
@@ -632,8 +633,6 @@ fn compare_asyncness<'tcx>(
/// For example, given the sample code:
///
/// ```
-/// #![feature(return_position_impl_trait_in_trait)]
-///
/// use std::ops::Deref;
///
/// trait Foo {
@@ -873,7 +872,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// RPITs.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(reported);
}
@@ -1010,7 +1009,11 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> {
});
self.types.insert(proj.def_id, (infer_ty, proj.args));
// Recurse into bounds
- for (pred, pred_span) in self.interner().explicit_item_bounds(proj.def_id).iter_instantiated_copied(self.interner(), proj.args) {
+ for (pred, pred_span) in self
+ .interner()
+ .explicit_item_bounds(proj.def_id)
+ .iter_instantiated_copied(self.interner(), proj.args)
+ {
let pred = pred.fold_with(self);
let pred = self.ocx.normalize(
&ObligationCause::misc(self.span, self.body_id),
@@ -1181,14 +1184,15 @@ fn report_trait_method_mismatch<'tcx>(
if trait_sig.inputs().len() == *i {
// Suggestion to change output type. We do not suggest in `async` functions
// to avoid complex logic or incorrect output.
- if let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind
+ if let ImplItemKind::Fn(sig, _) =
+ &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind
&& !sig.header.asyncness.is_async()
{
let msg = "change the output type to match the trait";
let ap = Applicability::MachineApplicable;
match sig.decl.output {
hir::FnRetTy::DefaultReturn(sp) => {
- let sugg = format!("-> {} ", trait_sig.output());
+ let sugg = format!(" -> {}", trait_sig.output());
diag.span_suggestion_verbose(sp, msg, sugg, ap);
}
hir::FnRetTy::Return(hir_ty) => {
@@ -1553,38 +1557,24 @@ fn compare_number_of_generics<'tcx>(
DiagnosticId::Error("E0049".into()),
);
- let mut suffix = None;
-
+ let msg =
+ format!("expected {trait_count} {kind} parameter{}", pluralize!(trait_count),);
if let Some(spans) = trait_spans {
let mut spans = spans.iter();
if let Some(span) = spans.next() {
- err.span_label(
- *span,
- format!(
- "expected {} {} parameter{}",
- trait_count,
- kind,
- pluralize!(trait_count),
- ),
- );
+ err.span_label(*span, msg);
}
for span in spans {
err.span_label(*span, "");
}
} else {
- suffix = Some(format!(", expected {trait_count}"));
+ err.span_label(tcx.def_span(trait_.def_id), msg);
}
if let Some(span) = span {
err.span_label(
span,
- format!(
- "found {} {} parameter{}{}",
- impl_count,
- kind,
- pluralize!(impl_count),
- suffix.unwrap_or_default(),
- ),
+ format!("found {} {} parameter{}", impl_count, kind, pluralize!(impl_count),),
);
}
@@ -2049,7 +2039,7 @@ fn compare_const_predicate_entailment<'tcx>(
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- return Err(infcx.err_ctxt().report_fulfillment_errors(&errors));
+ return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
}
let outlives_env = OutlivesEnvironment::new(param_env);
@@ -2142,7 +2132,7 @@ fn compare_type_predicate_entailment<'tcx>(
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(reported);
}
@@ -2173,127 +2163,9 @@ pub(super) fn check_type_bounds<'tcx>(
impl_trait_ref: ty::TraitRef<'tcx>,
) -> Result<(), ErrorGuaranteed> {
let param_env = tcx.param_env(impl_ty.def_id);
- let container_id = impl_ty.container_id(tcx);
- // Given
- //
- // impl<A, B> Foo<u32> for (A, B) {
- // type Bar<C> = Wrapper<A, B, C>
- // }
- //
- // - `impl_trait_ref` would be `<(A, B) as Foo<u32>>`
- // - `normalize_impl_ty_args` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
- // - `normalize_impl_ty` would be `Wrapper<A, B, ^0.0>`
- // - `rebased_args` would be `[(A, B), u32, ^0.0]`, combining the args from
- // the *trait* with the generic associated type parameters (as bound vars).
- //
- // A note regarding the use of bound vars here:
- // Imagine as an example
- // ```
- // trait Family {
- // type Member<C: Eq>;
- // }
- //
- // impl Family for VecFamily {
- // type Member<C: Eq> = i32;
- // }
- // ```
- // Here, we would generate
- // ```notrust
- // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) }
- // ```
- // when we really would like to generate
- // ```notrust
- // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) }
- // ```
- // But, this is probably fine, because although the first clause can be used with types C that
- // do not implement Eq, for it to cause some kind of problem, there would have to be a
- // VecFamily::Member<X> for some type X where !(X: Eq), that appears in the value of type
- // Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing
- // elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in
- // the trait (notably, that X: Eq and T: Family).
- let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
- smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len());
- // Extend the impl's identity args with late-bound GAT vars
- let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id).extend_to(
- tcx,
- impl_ty.def_id,
- |param, _| match param.kind {
- GenericParamDefKind::Type { .. } => {
- let kind = ty::BoundTyKind::Param(param.def_id, param.name);
- let bound_var = ty::BoundVariableKind::Ty(kind);
- bound_vars.push(bound_var);
- Ty::new_bound(
- tcx,
- ty::INNERMOST,
- ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
- )
- .into()
- }
- GenericParamDefKind::Lifetime => {
- let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
- let bound_var = ty::BoundVariableKind::Region(kind);
- bound_vars.push(bound_var);
- ty::Region::new_late_bound(
- tcx,
- ty::INNERMOST,
- ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
- )
- .into()
- }
- GenericParamDefKind::Const { .. } => {
- let bound_var = ty::BoundVariableKind::Const;
- bound_vars.push(bound_var);
- ty::Const::new_bound(
- tcx,
- ty::INNERMOST,
- ty::BoundVar::from_usize(bound_vars.len() - 1),
- tcx.type_of(param.def_id)
- .no_bound_vars()
- .expect("const parameter types cannot be generic"),
- )
- .into()
- }
- },
- );
- // When checking something like
- //
- // trait X { type Y: PartialEq<<Self as X>::Y> }
- // impl X for T { default type Y = S; }
- //
- // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
- // we want <T as X>::Y to normalize to S. This is valid because we are
- // checking the default value specifically here. Add this equality to the
- // ParamEnv for normalization specifically.
- let normalize_impl_ty = tcx.type_of(impl_ty.def_id).instantiate(tcx, normalize_impl_ty_args);
- let rebased_args = normalize_impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args);
- let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
- let normalize_param_env = {
- let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
- match normalize_impl_ty.kind() {
- ty::Alias(ty::Projection, proj)
- if proj.def_id == trait_ty.def_id && proj.args == rebased_args =>
- {
- // Don't include this predicate if the projected type is
- // exactly the same as the projection. This can occur in
- // (somewhat dubious) code like this:
- //
- // impl<T> X for T where T: X { type Y = <T as X>::Y; }
- }
- _ => predicates.push(ty::Clause::from_projection_clause(
- tcx,
- ty::Binder::bind_with_vars(
- ty::ProjectionPredicate {
- projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_args),
- term: normalize_impl_ty.into(),
- },
- bound_vars,
- ),
- )),
- };
- ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing)
- };
- debug!(?normalize_param_env);
+ debug!(?param_env);
+ let container_id = impl_ty.container_id(tcx);
let impl_ty_def_id = impl_ty.def_id.expect_local();
let impl_ty_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id);
let rebased_args = impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args);
@@ -2345,6 +2217,11 @@ pub(super) fn check_type_bounds<'tcx>(
.collect();
debug!("check_type_bounds: item_bounds={:?}", obligations);
+ // Normalize predicates with the assumption that the GAT may always normalize
+ // to its definition type. This should be the param-env we use to *prove* the
+ // predicate too, but we don't do that because of performance issues.
+ // See <https://github.com/rust-lang/rust/pull/117542#issue-1976337685>.
+ let normalize_param_env = param_env_with_gat_bounds(tcx, impl_ty, impl_trait_ref);
for mut obligation in util::elaborate(tcx, obligations) {
let normalized_predicate =
ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate);
@@ -2357,7 +2234,7 @@ pub(super) fn check_type_bounds<'tcx>(
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(reported);
}
@@ -2368,6 +2245,171 @@ pub(super) fn check_type_bounds<'tcx>(
ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env)
}
+/// Install projection predicates that allow GATs to project to their own
+/// definition types. This is not allowed in general in cases of default
+/// associated types in trait definitions, or when specialization is involved,
+/// but is needed when checking these definition types actually satisfy the
+/// trait bounds of the GAT.
+///
+/// # How it works
+///
+/// ```ignore (example)
+/// impl<A, B> Foo<u32> for (A, B) {
+/// type Bar<C> = Wrapper<A, B, C>
+/// }
+/// ```
+///
+/// - `impl_trait_ref` would be `<(A, B) as Foo<u32>>`
+/// - `normalize_impl_ty_args` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
+/// - `normalize_impl_ty` would be `Wrapper<A, B, ^0.0>`
+/// - `rebased_args` would be `[(A, B), u32, ^0.0]`, combining the args from
+/// the *trait* with the generic associated type parameters (as bound vars).
+///
+/// A note regarding the use of bound vars here:
+/// Imagine as an example
+/// ```
+/// trait Family {
+/// type Member<C: Eq>;
+/// }
+///
+/// impl Family for VecFamily {
+/// type Member<C: Eq> = i32;
+/// }
+/// ```
+/// Here, we would generate
+/// ```ignore (pseudo-rust)
+/// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) }
+/// ```
+///
+/// when we really would like to generate
+/// ```ignore (pseudo-rust)
+/// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) }
+/// ```
+///
+/// But, this is probably fine, because although the first clause can be used with types `C` that
+/// do not implement `Eq`, for it to cause some kind of problem, there would have to be a
+/// `VecFamily::Member<X>` for some type `X` where `!(X: Eq)`, that appears in the value of type
+/// `Member<C: Eq> = ....` That type would fail a well-formedness check that we ought to be doing
+/// elsewhere, which would check that any `<T as Family>::Member<X>` meets the bounds declared in
+/// the trait (notably, that `X: Eq` and `T: Family`).
+fn param_env_with_gat_bounds<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_ty: ty::AssocItem,
+ impl_trait_ref: ty::TraitRef<'tcx>,
+) -> ty::ParamEnv<'tcx> {
+ let param_env = tcx.param_env(impl_ty.def_id);
+ let container_id = impl_ty.container_id(tcx);
+ let mut predicates = param_env.caller_bounds().to_vec();
+
+ // for RPITITs, we should install predicates that allow us to project all
+ // of the RPITITs associated with the same body. This is because checking
+ // the item bounds of RPITITs often involves nested RPITITs having to prove
+ // bounds about themselves.
+ let impl_tys_to_install = match impl_ty.opt_rpitit_info {
+ None => vec![impl_ty],
+ Some(
+ ty::ImplTraitInTraitData::Impl { fn_def_id }
+ | ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
+ ) => tcx
+ .associated_types_for_impl_traits_in_associated_fn(fn_def_id)
+ .iter()
+ .map(|def_id| tcx.associated_item(*def_id))
+ .collect(),
+ };
+
+ for impl_ty in impl_tys_to_install {
+ let trait_ty = match impl_ty.container {
+ ty::AssocItemContainer::TraitContainer => impl_ty,
+ ty::AssocItemContainer::ImplContainer => {
+ tcx.associated_item(impl_ty.trait_item_def_id.unwrap())
+ }
+ };
+
+ let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
+ smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len());
+ // Extend the impl's identity args with late-bound GAT vars
+ let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id)
+ .extend_to(tcx, impl_ty.def_id, |param, _| match param.kind {
+ GenericParamDefKind::Type { .. } => {
+ let kind = ty::BoundTyKind::Param(param.def_id, param.name);
+ let bound_var = ty::BoundVariableKind::Ty(kind);
+ bound_vars.push(bound_var);
+ Ty::new_bound(
+ tcx,
+ ty::INNERMOST,
+ ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
+ )
+ .into()
+ }
+ GenericParamDefKind::Lifetime => {
+ let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
+ let bound_var = ty::BoundVariableKind::Region(kind);
+ bound_vars.push(bound_var);
+ ty::Region::new_late_bound(
+ tcx,
+ ty::INNERMOST,
+ ty::BoundRegion {
+ var: ty::BoundVar::from_usize(bound_vars.len() - 1),
+ kind,
+ },
+ )
+ .into()
+ }
+ GenericParamDefKind::Const { .. } => {
+ let bound_var = ty::BoundVariableKind::Const;
+ bound_vars.push(bound_var);
+ ty::Const::new_bound(
+ tcx,
+ ty::INNERMOST,
+ ty::BoundVar::from_usize(bound_vars.len() - 1),
+ tcx.type_of(param.def_id)
+ .no_bound_vars()
+ .expect("const parameter types cannot be generic"),
+ )
+ .into()
+ }
+ });
+ // When checking something like
+ //
+ // trait X { type Y: PartialEq<<Self as X>::Y> }
+ // impl X for T { default type Y = S; }
+ //
+ // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
+ // we want <T as X>::Y to normalize to S. This is valid because we are
+ // checking the default value specifically here. Add this equality to the
+ // ParamEnv for normalization specifically.
+ let normalize_impl_ty =
+ tcx.type_of(impl_ty.def_id).instantiate(tcx, normalize_impl_ty_args);
+ let rebased_args =
+ normalize_impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args);
+ let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
+
+ match normalize_impl_ty.kind() {
+ ty::Alias(ty::Projection, proj)
+ if proj.def_id == trait_ty.def_id && proj.args == rebased_args =>
+ {
+ // Don't include this predicate if the projected type is
+ // exactly the same as the projection. This can occur in
+ // (somewhat dubious) code like this:
+ //
+ // impl<T> X for T where T: X { type Y = <T as X>::Y; }
+ }
+ _ => predicates.push(
+ ty::Binder::bind_with_vars(
+ ty::ProjectionPredicate {
+ projection_ty: ty::AliasTy::new(tcx, trait_ty.def_id, rebased_args),
+ term: normalize_impl_ty.into(),
+ },
+ bound_vars,
+ )
+ .to_predicate(tcx),
+ ),
+ };
+ }
+
+ ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing)
+}
+
fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
match impl_item.kind {
ty::AssocKind::Const => "const",
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index d9e0e87eb..bc5029a1d 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -23,8 +23,12 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
if !tcx.impl_method_has_trait_impl_trait_tys(impl_m.def_id) {
return;
}
- // crate-private traits don't have any library guarantees, there's no need to do this check.
- if !tcx.visibility(trait_m.container_id(tcx)).is_public() {
+ // unreachable traits don't have any library guarantees, there's no need to do this check.
+ if trait_m
+ .container_id(tcx)
+ .as_local()
+ .is_some_and(|trait_def_id| !tcx.effective_visibilities(()).is_reachable(trait_def_id))
+ {
return;
}
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index 3cd3f5bcf..6681292c9 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -158,7 +158,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
ocx.register_bound(cause, param_env, norm_return_ty, term_did);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors);
+ infcx.err_ctxt().report_fulfillment_errors(errors);
error = true;
}
// now we can take the return type of the given main function
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 5fa65f33c..15c5558fc 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -90,9 +90,8 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{GenericArgs, GenericArgsRef};
use rustc_session::parse::feature_err;
-use rustc_span::source_map::DUMMY_SP;
use rustc_span::symbol::{kw, Ident};
-use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol};
+use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
@@ -114,7 +113,7 @@ pub fn provide(providers: &mut Providers) {
region_scope_tree,
collect_return_position_impl_trait_in_trait_tys,
compare_impl_const: compare_impl_item::compare_impl_const_raw,
- check_generator_obligations: check::check_generator_obligations,
+ check_coroutine_obligations: check::check_coroutine_obligations,
..*providers
};
}
@@ -588,7 +587,7 @@ pub fn check_function_signature<'tcx>(
Ok(()) => {
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors);
+ infcx.err_ctxt().report_fulfillment_errors(errors);
return;
}
}
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 463fab93e..40b33117f 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -598,7 +598,7 @@ fn resolve_local<'tcx>(
}
// Make sure we visit the initializer first, so expr_and_pat_count remains correct.
- // The correct order, as shared between generator_interior, drop_ranges and intravisitor,
+ // The correct order, as shared between coroutine_interior, drop_ranges and intravisitor,
// is to walk initializer, followed by pattern bindings, finally followed by the `else` block.
if let Some(expr) = init {
visitor.visit_expr(expr);
@@ -825,7 +825,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
resolve_local(self, None, Some(&body.value));
}
- if body.generator_kind.is_some() {
+ if body.coroutine_kind.is_some() {
self.scope_tree.body_expr_count.insert(body_id, self.expr_and_pat_count);
}
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 77614a9a4..eb4491b89 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -93,8 +93,9 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
span: Span,
body_def_id: LocalDefId,
f: F,
-) where
- F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>),
+) -> Result<(), ErrorGuaranteed>
+where
+ F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>) -> Result<(), ErrorGuaranteed>,
{
let param_env = tcx.param_env(body_def_id);
let infcx = &tcx.infer_ctxt().build();
@@ -105,42 +106,48 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
if !tcx.features().trivial_bounds {
wfcx.check_false_global_bounds()
}
- f(&mut wfcx);
+ f(&mut wfcx)?;
- let assumed_wf_types = match wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)
- {
- Ok(wf_types) => wf_types,
- Err(_guar) => return,
- };
+ let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?;
let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, assumed_wf_types);
let errors = wfcx.select_all_or_error();
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors);
- return;
+ let err = infcx.err_ctxt().report_fulfillment_errors(errors);
+ if tcx.sess.err_count() > 0 {
+ return Err(err);
+ } else {
+ // HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs causes an
+ // error (delay_span_bug) during normalization, without reporting an error, so we need to act as if
+ // no error happened, in order to let our callers continue and report an error later in
+ // check_impl_items_against_trait.
+ return Ok(());
+ }
}
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
- let _ = wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env);
+ wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env)?;
+ infcx.tainted_by_errors().error_reported()
}
-fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
+fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorGuaranteed> {
let node = tcx.hir().owner(def_id);
- match node {
- hir::OwnerNode::Crate(_) => {}
+ let mut res = match node {
+ hir::OwnerNode::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"),
hir::OwnerNode::Item(item) => check_item(tcx, item),
hir::OwnerNode::TraitItem(item) => check_trait_item(tcx, item),
hir::OwnerNode::ImplItem(item) => check_impl_item(tcx, item),
hir::OwnerNode::ForeignItem(item) => check_foreign_item(tcx, item),
- }
+ };
if let Some(generics) = node.generics() {
for param in generics.params {
- check_param_wf(tcx, param)
+ res = res.and(check_param_wf(tcx, param));
}
}
+ res
}
/// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are
@@ -157,7 +164,7 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
/// not included it frequently leads to confusing errors in fn bodies. So it's better to check
/// the types first.
#[instrument(skip(tcx), level = "debug")]
-fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
+fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<(), ErrorGuaranteed> {
let def_id = item.owner_id.def_id;
debug!(
@@ -187,31 +194,32 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
let is_auto = tcx
.impl_trait_ref(def_id)
.is_some_and(|trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id));
+ let mut res = Ok(());
if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) {
let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span);
let mut err =
tcx.sess.struct_span_err(sp, "impls of auto traits cannot be default");
err.span_labels(impl_.defaultness_span, "default because of this");
err.span_label(sp, "auto trait");
- err.emit();
+ res = Err(err.emit());
}
// We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span.
match (tcx.impl_polarity(def_id), impl_.polarity) {
(ty::ImplPolarity::Positive, _) => {
- check_impl(tcx, item, impl_.self_ty, &impl_.of_trait);
+ res = res.and(check_impl(tcx, item, impl_.self_ty, &impl_.of_trait));
}
(ty::ImplPolarity::Negative, ast::ImplPolarity::Negative(span)) => {
// FIXME(#27579): what amount of WF checking do we need for neg impls?
if let hir::Defaultness::Default { .. } = impl_.defaultness {
let mut spans = vec![span];
spans.extend(impl_.defaultness_span);
- struct_span_err!(
+ res = Err(struct_span_err!(
tcx.sess,
spans,
E0750,
"negative impls cannot be default impls"
)
- .emit();
+ .emit());
}
}
(ty::ImplPolarity::Reservation, _) => {
@@ -219,49 +227,52 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
}
_ => unreachable!(),
}
+ res
}
hir::ItemKind::Fn(ref sig, ..) => {
- check_item_fn(tcx, def_id, item.ident, item.span, sig.decl);
+ check_item_fn(tcx, def_id, item.ident, item.span, sig.decl)
}
hir::ItemKind::Static(ty, ..) => {
- check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid);
+ check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid)
}
hir::ItemKind::Const(ty, ..) => {
- check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid);
+ check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid)
}
hir::ItemKind::Struct(_, ast_generics) => {
- check_type_defn(tcx, item, false);
+ let res = check_type_defn(tcx, item, false);
check_variances_for_type_defn(tcx, item, ast_generics);
+ res
}
hir::ItemKind::Union(_, ast_generics) => {
- check_type_defn(tcx, item, true);
+ let res = check_type_defn(tcx, item, true);
check_variances_for_type_defn(tcx, item, ast_generics);
+ res
}
hir::ItemKind::Enum(_, ast_generics) => {
- check_type_defn(tcx, item, true);
+ let res = check_type_defn(tcx, item, true);
check_variances_for_type_defn(tcx, item, ast_generics);
+ res
}
- hir::ItemKind::Trait(..) => {
- check_trait(tcx, item);
- }
- hir::ItemKind::TraitAlias(..) => {
- check_trait(tcx, item);
- }
+ hir::ItemKind::Trait(..) => check_trait(tcx, item),
+ hir::ItemKind::TraitAlias(..) => check_trait(tcx, item),
// `ForeignItem`s are handled separately.
- hir::ItemKind::ForeignMod { .. } => {}
+ hir::ItemKind::ForeignMod { .. } => Ok(()),
hir::ItemKind::TyAlias(hir_ty, ast_generics) => {
if tcx.type_alias_is_lazy(item.owner_id) {
// Bounds of lazy type aliases and of eager ones that contain opaque types are respected.
// E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`.
- check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow);
+ let res = check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow);
check_variances_for_type_defn(tcx, item, ast_generics);
+ res
+ } else {
+ Ok(())
}
}
- _ => {}
+ _ => Ok(()),
}
}
-fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) {
+fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) -> Result<(), ErrorGuaranteed> {
let def_id = item.owner_id.def_id;
debug!(
@@ -276,11 +287,14 @@ fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) {
hir::ForeignItemKind::Static(ty, ..) => {
check_item_type(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail)
}
- hir::ForeignItemKind::Type => (),
+ hir::ForeignItemKind::Type => Ok(()),
}
}
-fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
+fn check_trait_item(
+ tcx: TyCtxt<'_>,
+ trait_item: &hir::TraitItem<'_>,
+) -> Result<(), ErrorGuaranteed> {
let def_id = trait_item.owner_id.def_id;
let (method_sig, span) = match trait_item.kind {
@@ -289,18 +303,19 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
_ => (None, trait_item.span),
};
check_object_unsafe_self_trait_by_name(tcx, trait_item);
- check_associated_item(tcx, def_id, span, method_sig);
+ let mut res = check_associated_item(tcx, def_id, span, method_sig);
if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) {
for &assoc_ty_def_id in tcx.associated_types_for_impl_traits_in_associated_fn(def_id) {
- check_associated_item(
+ res = res.and(check_associated_item(
tcx,
assoc_ty_def_id.expect_local(),
tcx.def_span(assoc_ty_def_id),
None,
- );
+ ));
}
}
+ res
}
/// Require that the user writes where clauses on GATs for the implicit
@@ -315,9 +330,10 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
/// fn into_iter<'a>(&'a self) -> Self::Iter<'a>;
/// }
/// ```
-fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRef]) {
+fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
// Associates every GAT's def_id to a list of possibly missing bounds detected by this lint.
let mut required_bounds_by_item = FxHashMap::default();
+ let associated_items = tcx.associated_items(trait_def_id);
// Loop over all GATs together, because if this lint suggests adding a where-clause bound
// to one GAT, it might then require us to an additional bound on another GAT.
@@ -326,8 +342,8 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
// those GATs.
loop {
let mut should_continue = false;
- for gat_item in associated_items {
- let gat_def_id = gat_item.id.owner_id;
+ for gat_item in associated_items.in_definition_order() {
+ let gat_def_id = gat_item.def_id.expect_local();
let gat_item = tcx.associated_item(gat_def_id);
// If this item is not an assoc ty, or has no args, then it's not a GAT
if gat_item.kind != ty::AssocKind::Type {
@@ -343,8 +359,8 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
// This is calculated by taking the intersection of the bounds that each item
// constrains the GAT with individually.
let mut new_required_bounds: Option<FxHashSet<ty::Clause<'_>>> = None;
- for item in associated_items {
- let item_def_id = item.id.owner_id;
+ for item in associated_items.in_definition_order() {
+ let item_def_id = item.def_id.expect_local();
// Skip our own GAT, since it does not constrain itself at all.
if item_def_id == gat_def_id {
continue;
@@ -352,9 +368,9 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
let param_env = tcx.param_env(item_def_id);
- let item_required_bounds = match item.kind {
+ let item_required_bounds = match tcx.associated_item(item_def_id).kind {
// In our example, this corresponds to `into_iter` method
- hir::AssocItemKind::Fn { .. } => {
+ ty::AssocKind::Fn => {
// For methods, we check the function signature's return type for any GATs
// to constrain. In the `into_iter` case, we see that the return type
// `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from.
@@ -370,12 +386,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
// We also assume that all of the function signature's parameter types
// are well formed.
&sig.inputs().iter().copied().collect(),
- gat_def_id.def_id,
+ gat_def_id,
gat_generics,
)
}
// In our example, this corresponds to the `Iter` and `Item` associated types
- hir::AssocItemKind::Type => {
+ ty::AssocKind::Type => {
// If our associated item is a GAT with missing bounds, add them to
// the param-env here. This allows this GAT to propagate missing bounds
// to other GATs.
@@ -392,11 +408,11 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
.instantiate_identity_iter_copied()
.collect::<Vec<_>>(),
&FxIndexSet::default(),
- gat_def_id.def_id,
+ gat_def_id,
gat_generics,
)
}
- hir::AssocItemKind::Const => None,
+ ty::AssocKind::Const => None,
};
if let Some(item_required_bounds) = item_required_bounds {
@@ -432,7 +448,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
}
for (gat_def_id, required_bounds) in required_bounds_by_item {
- let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id.def_id);
+ // Don't suggest adding `Self: 'a` to a GAT that can't be named
+ if tcx.is_impl_trait_in_trait(gat_def_id.to_def_id()) {
+ continue;
+ }
+
+ let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id);
debug!(?required_bounds);
let param_env = tcx.param_env(gat_def_id);
@@ -442,21 +463,16 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
!region_known_to_outlive(
tcx,
- gat_def_id.def_id,
+ gat_def_id,
param_env,
&FxIndexSet::default(),
a,
b,
)
}
- ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => !ty_known_to_outlive(
- tcx,
- gat_def_id.def_id,
- param_env,
- &FxIndexSet::default(),
- a,
- b,
- ),
+ ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
+ !ty_known_to_outlive(tcx, gat_def_id, param_env, &FxIndexSet::default(), a, b)
+ }
_ => bug!("Unexpected ClauseKind"),
})
.map(|clause| clause.to_string())
@@ -535,7 +551,7 @@ fn augment_param_env<'tcx>(
fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- item_def_id: hir::OwnerId,
+ item_def_id: LocalDefId,
to_check: T,
wf_tys: &FxIndexSet<Ty<'tcx>>,
gat_def_id: LocalDefId,
@@ -568,7 +584,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
// reflected in a where clause on the GAT itself.
for (ty, ty_idx) in &types {
// In our example, requires that `Self: 'a`
- if ty_known_to_outlive(tcx, item_def_id.def_id, param_env, &wf_tys, *ty, *region_a) {
+ if ty_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *ty, *region_a) {
debug!(?ty_idx, ?region_a_idx);
debug!("required clause: {ty} must outlive {region_a}");
// Translate into the generic parameters of the GAT. In
@@ -607,14 +623,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
if matches!(**region_b, ty::ReStatic | ty::ReError(_)) || region_a == region_b {
continue;
}
- if region_known_to_outlive(
- tcx,
- item_def_id.def_id,
- param_env,
- &wf_tys,
- *region_a,
- *region_b,
- ) {
+ if region_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *region_a, *region_b) {
debug!(?region_a_idx, ?region_b_idx);
debug!("required clause: {region_a} must outlive {region_b}");
// Translate into the generic parameters of the GAT.
@@ -833,7 +842,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
}
}
-fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) {
+fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) -> Result<(), ErrorGuaranteed> {
let (method_sig, span) = match impl_item.kind {
hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span),
// Constrain binding and overflow error spans to `<Ty>` in `type foo = <Ty>`.
@@ -841,13 +850,13 @@ fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) {
_ => (None, impl_item.span),
};
- check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig);
+ check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig)
}
-fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
+fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ErrorGuaranteed> {
match param.kind {
// We currently only check wf of const params here.
- hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => (),
+ hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => Ok(()),
// Const parameters are well formed if their type is structural match.
hir::GenericParamKind::Const { ty: hir_ty, default: _ } => {
@@ -867,68 +876,67 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
ty,
trait_def_id,
);
- });
+ Ok(())
+ })
} else {
- let diag = match ty.kind() {
- ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
- ty::FnPtr(_) => Some(tcx.sess.struct_span_err(
+ let mut diag = match ty.kind() {
+ ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => return Ok(()),
+ ty::FnPtr(_) => tcx.sess.struct_span_err(
hir_ty.span,
"using function pointers as const generic parameters is forbidden",
- )),
- ty::RawPtr(_) => Some(tcx.sess.struct_span_err(
+ ),
+ ty::RawPtr(_) => tcx.sess.struct_span_err(
hir_ty.span,
"using raw pointers as const generic parameters is forbidden",
- )),
- _ => Some(tcx.sess.struct_span_err(
+ ),
+ _ => tcx.sess.struct_span_err(
hir_ty.span,
format!("`{}` is forbidden as the type of a const generic parameter", ty),
- )),
+ ),
};
- if let Some(mut diag) = diag {
- diag.note("the only supported types are integers, `bool` and `char`");
+ diag.note("the only supported types are integers, `bool` and `char`");
- let cause = ObligationCause::misc(hir_ty.span, param.def_id);
- let may_suggest_feature = match type_allowed_to_implement_const_param_ty(
- tcx,
- tcx.param_env(param.def_id),
- ty,
- cause,
- ) {
- // Can never implement `ConstParamTy`, don't suggest anything.
- Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => false,
- // May be able to implement `ConstParamTy`. Only emit the feature help
- // if the type is local, since the user may be able to fix the local type.
- Err(ConstParamTyImplementationError::InfrigingFields(..)) => {
- fn ty_is_local(ty: Ty<'_>) -> bool {
- match ty.kind() {
- ty::Adt(adt_def, ..) => adt_def.did().is_local(),
- // Arrays and slices use the inner type's `ConstParamTy`.
- ty::Array(ty, ..) => ty_is_local(*ty),
- ty::Slice(ty) => ty_is_local(*ty),
- // `&` references use the inner type's `ConstParamTy`.
- // `&mut` are not supported.
- ty::Ref(_, ty, ast::Mutability::Not) => ty_is_local(*ty),
- // Say that a tuple is local if any of its components are local.
- // This is not strictly correct, but it's likely that the user can fix the local component.
- ty::Tuple(tys) => tys.iter().any(|ty| ty_is_local(ty)),
- _ => false,
- }
+ let cause = ObligationCause::misc(hir_ty.span, param.def_id);
+ let may_suggest_feature = match type_allowed_to_implement_const_param_ty(
+ tcx,
+ tcx.param_env(param.def_id),
+ ty,
+ cause,
+ ) {
+ // Can never implement `ConstParamTy`, don't suggest anything.
+ Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => false,
+ // May be able to implement `ConstParamTy`. Only emit the feature help
+ // if the type is local, since the user may be able to fix the local type.
+ Err(ConstParamTyImplementationError::InfrigingFields(..)) => {
+ fn ty_is_local(ty: Ty<'_>) -> bool {
+ match ty.kind() {
+ ty::Adt(adt_def, ..) => adt_def.did().is_local(),
+ // Arrays and slices use the inner type's `ConstParamTy`.
+ ty::Array(ty, ..) => ty_is_local(*ty),
+ ty::Slice(ty) => ty_is_local(*ty),
+ // `&` references use the inner type's `ConstParamTy`.
+ // `&mut` are not supported.
+ ty::Ref(_, ty, ast::Mutability::Not) => ty_is_local(*ty),
+ // Say that a tuple is local if any of its components are local.
+ // This is not strictly correct, but it's likely that the user can fix the local component.
+ ty::Tuple(tys) => tys.iter().any(|ty| ty_is_local(ty)),
+ _ => false,
}
-
- ty_is_local(ty)
}
- // Implments `ConstParamTy`, suggest adding the feature to enable.
- Ok(..) => true,
- };
- if may_suggest_feature && tcx.sess.is_nightly_build() {
- diag.help(
+
+ ty_is_local(ty)
+ }
+ // Implments `ConstParamTy`, suggest adding the feature to enable.
+ Ok(..) => true,
+ };
+ if may_suggest_feature && tcx.sess.is_nightly_build() {
+ diag.help(
"add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types",
);
- }
-
- diag.emit();
}
+
+ Err(diag.emit())
}
}
}
@@ -940,7 +948,7 @@ fn check_associated_item(
item_id: LocalDefId,
span: Span,
sig_if_method: Option<&hir::FnSig<'_>>,
-) {
+) -> Result<(), ErrorGuaranteed> {
let loc = Some(WellFormedLoc::Ty(item_id));
enter_wf_checking_ctxt(tcx, span, item_id, |wfcx| {
let item = tcx.associated_item(item_id);
@@ -955,6 +963,7 @@ fn check_associated_item(
let ty = tcx.type_of(item.def_id).instantiate_identity();
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into());
+ Ok(())
}
ty::AssocKind::Fn => {
let sig = tcx.fn_sig(item.def_id).instantiate_identity();
@@ -966,7 +975,7 @@ fn check_associated_item(
hir_sig.decl,
item.def_id.expect_local(),
);
- check_method_receiver(wfcx, hir_sig, item, self_ty);
+ check_method_receiver(wfcx, hir_sig, item, self_ty)
}
ty::AssocKind::Type => {
if let ty::AssocItemContainer::TraitContainer = item.container {
@@ -977,6 +986,7 @@ fn check_associated_item(
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into());
}
+ Ok(())
}
}
})
@@ -992,7 +1002,11 @@ fn item_adt_kind(kind: &ItemKind<'_>) -> Option<AdtKind> {
}
/// In a type definition, we check that to ensure that the types of the fields are well-formed.
-fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: bool) {
+fn check_type_defn<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ item: &hir::Item<'tcx>,
+ all_sized: bool,
+) -> Result<(), ErrorGuaranteed> {
let _ = tcx.representability(item.owner_id.def_id);
let adt_def = tcx.adt_def(item.owner_id);
@@ -1087,11 +1101,12 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b
}
check_where_clauses(wfcx, item.span, item.owner_id.def_id);
- });
+ Ok(())
+ })
}
#[instrument(skip(tcx, item))]
-fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
+fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) -> Result<(), ErrorGuaranteed> {
debug!(?item.owner_id);
let def_id = item.owner_id.def_id;
@@ -1110,14 +1125,16 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
}
}
- enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| {
- check_where_clauses(wfcx, item.span, def_id)
+ let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| {
+ check_where_clauses(wfcx, item.span, def_id);
+ Ok(())
});
// Only check traits, don't check trait aliases
- if let hir::ItemKind::Trait(_, _, _, _, items) = item.kind {
- check_gat_where_clauses(tcx, items);
+ if let hir::ItemKind::Trait(..) = item.kind {
+ check_gat_where_clauses(tcx, item.owner_id.def_id);
}
+ res
}
/// Checks all associated type defaults of trait `trait_def_id`.
@@ -1131,11 +1148,11 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt
let wf_obligations =
bounds.instantiate_identity_iter_copied().flat_map(|(bound, bound_span)| {
let normalized_bound = wfcx.normalize(span, None, bound);
- traits::wf::predicate_obligations(
+ traits::wf::clause_obligations(
wfcx.infcx,
wfcx.param_env,
wfcx.body_def_id,
- normalized_bound.as_predicate(),
+ normalized_bound,
bound_span,
)
});
@@ -1149,10 +1166,11 @@ fn check_item_fn(
ident: Ident,
span: Span,
decl: &hir::FnDecl<'_>,
-) {
+) -> Result<(), ErrorGuaranteed> {
enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| {
let sig = tcx.fn_sig(def_id).instantiate_identity();
check_fn_or_method(wfcx, ident.span, sig, decl, def_id);
+ Ok(())
})
}
@@ -1167,7 +1185,7 @@ fn check_item_type(
item_id: LocalDefId,
ty_span: Span,
unsized_handling: UnsizedHandling,
-) {
+) -> Result<(), ErrorGuaranteed> {
debug!("check_item_type: {:?}", item_id);
enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| {
@@ -1207,7 +1225,8 @@ fn check_item_type(
tcx.require_lang_item(LangItem::Sync, Some(ty_span)),
);
}
- });
+ Ok(())
+ })
}
#[instrument(level = "debug", skip(tcx, ast_self_ty, ast_trait_ref))]
@@ -1216,7 +1235,7 @@ fn check_impl<'tcx>(
item: &'tcx hir::Item<'tcx>,
ast_self_ty: &hir::Ty<'_>,
ast_trait_ref: &Option<hir::TraitRef<'_>>,
-) {
+) -> Result<(), ErrorGuaranteed> {
enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
match ast_trait_ref {
Some(ast_trait_ref) => {
@@ -1235,7 +1254,7 @@ fn check_impl<'tcx>(
wfcx.infcx,
wfcx.param_env,
wfcx.body_def_id,
- &trait_pred,
+ trait_pred,
ast_trait_ref.path.span,
item,
);
@@ -1265,7 +1284,8 @@ fn check_impl<'tcx>(
}
check_where_clauses(wfcx, item.span, item.owner_id.def_id);
- });
+ Ok(())
+ })
}
/// Checks where-clauses and inline bounds that are declared on `def_id`.
@@ -1444,13 +1464,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
debug!(?predicates.predicates);
assert_eq!(predicates.predicates.len(), predicates.spans.len());
let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| {
- traits::wf::predicate_obligations(
- infcx,
- wfcx.param_env,
- wfcx.body_def_id,
- p.as_predicate(),
- sp,
- )
+ traits::wf::clause_obligations(infcx, wfcx.param_env, wfcx.body_def_id, p, sp)
});
let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect();
wfcx.register_obligations(obligations);
@@ -1543,11 +1557,11 @@ fn check_method_receiver<'tcx>(
fn_sig: &hir::FnSig<'_>,
method: ty::AssocItem,
self_ty: Ty<'tcx>,
-) {
+) -> Result<(), ErrorGuaranteed> {
let tcx = wfcx.tcx();
if !method.fn_has_self_parameter {
- return;
+ return Ok(());
}
let span = fn_sig.decl.inputs[0].span;
@@ -1566,11 +1580,11 @@ fn check_method_receiver<'tcx>(
if tcx.features().arbitrary_self_types {
if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) {
// Report error; `arbitrary_self_types` was enabled.
- e0307(tcx, span, receiver_ty);
+ return Err(e0307(tcx, span, receiver_ty));
}
} else {
if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, false) {
- if receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) {
+ return Err(if receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) {
// Report error; would have worked with `arbitrary_self_types`.
feature_err(
&tcx.sess.parse_sess,
@@ -1582,16 +1596,17 @@ fn check_method_receiver<'tcx>(
),
)
.help(HELP_FOR_SELF_TYPE)
- .emit();
+ .emit()
} else {
// Report error; would not have worked with `arbitrary_self_types`.
- e0307(tcx, span, receiver_ty);
- }
+ e0307(tcx, span, receiver_ty)
+ });
}
}
+ Ok(())
}
-fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) {
+fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) -> ErrorGuaranteed {
struct_span_err!(
tcx.sess.diagnostic(),
span,
@@ -1600,7 +1615,7 @@ fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) {
)
.note("type of `self` must be `Self` or a type that dereferences to it")
.help(HELP_FOR_SELF_TYPE)
- .emit();
+ .emit()
}
/// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If
@@ -1892,12 +1907,12 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
}
}
-fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) {
+fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> {
let items = tcx.hir_module_items(module);
- items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id));
- items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id));
- items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id));
- items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id));
+ let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id));
+ res = res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
+ res = res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
+ res.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id)))
}
fn error_392(
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index be70acfc3..e5e192e00 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -162,7 +162,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
// trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else
// in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
// even if they do not carry that attribute.
- use rustc_type_ir::sty::TyKind::*;
+ use rustc_type_ir::TyKind::*;
match (source.kind(), target.kind()) {
(&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
if infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, r_a, *r_b).is_ok()
@@ -261,7 +261,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
}
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors);
+ infcx.err_ctxt().report_fulfillment_errors(errors);
}
// Finally, resolve all regions.
@@ -470,7 +470,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
ocx.register_obligation(obligation);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors);
+ infcx.err_ctxt().report_fulfillment_errors(errors);
}
// Finally, resolve all regions.
@@ -550,9 +550,11 @@ fn infringing_fields_error(
.entry((ty.clone(), predicate.clone()))
.or_default()
.push(origin.span());
- if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() {
- bounds.push((b.to_string(), a.to_string(), None));
- }
+ if let ty::RegionKind::ReEarlyBound(ebr) = *b
+ && ebr.has_name()
+ {
+ bounds.push((b.to_string(), a.to_string(), None));
+ }
}
RegionResolutionError::GenericBoundFailure(origin, a, b) => {
let predicate = format!("{a}: {b}");
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 0042d683b..1b4df31b5 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -155,8 +155,8 @@ impl<'tcx> InherentCollect<'tcx> {
}
ty::FnDef(..)
| ty::Closure(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..)
| ty::Bound(..)
| ty::Placeholder(_)
| ty::Infer(_) => {
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 69020b1f1..7eeb78374 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -2,8 +2,7 @@
//! crate or pertains to a type defined in this crate.
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{struct_span_err, DelayDm};
-use rustc_errors::{Diagnostic, ErrorGuaranteed};
+use rustc_errors::{DelayDm, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_middle::ty::util::CheckRegions;
use rustc_middle::ty::GenericArgs;
@@ -17,6 +16,8 @@ use rustc_span::Span;
use rustc_trait_selection::traits;
use std::ops::ControlFlow;
+use crate::errors;
+
#[instrument(skip(tcx), level = "debug")]
pub(crate) fn orphan_check_impl(
tcx: TyCtxt<'_>,
@@ -243,8 +244,8 @@ fn do_orphan_check_impl<'tcx>(
| ty::Tuple(..) => (LocalImpl::Allow, NonlocalImpl::DisallowOther),
ty::Closure(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(..) => {
@@ -259,49 +260,30 @@ fn do_orphan_check_impl<'tcx>(
match local_impl {
LocalImpl::Allow => {}
LocalImpl::Disallow { problematic_kind } => {
- let msg = format!(
- "traits with a default impl, like `{trait}`, \
- cannot be implemented for {problematic_kind} `{self_ty}`",
- trait = tcx.def_path_str(trait_def_id),
- );
- let label = format!(
- "a trait object implements `{trait}` if and only if `{trait}` \
- is one of the trait object's trait bounds",
- trait = tcx.def_path_str(trait_def_id),
- );
- let sp = tcx.def_span(def_id);
- let reported =
- struct_span_err!(tcx.sess, sp, E0321, "{}", msg).note(label).emit();
- return Err(reported);
+ return Err(tcx.sess.emit_err(errors::TraitsWithDefaultImpl {
+ span: tcx.def_span(def_id),
+ traits: tcx.def_path_str(trait_def_id),
+ problematic_kind,
+ self_ty,
+ }));
}
}
} else {
- if let Some((msg, label)) = match nonlocal_impl {
- NonlocalImpl::Allow => None,
- NonlocalImpl::DisallowBecauseNonlocal => Some((
- format!(
- "cross-crate traits with a default impl, like `{}`, \
- can only be implemented for a struct/enum type \
- defined in the current crate",
- tcx.def_path_str(trait_def_id)
- ),
- "can't implement cross-crate trait for type in another crate",
- )),
- NonlocalImpl::DisallowOther => Some((
- format!(
- "cross-crate traits with a default impl, like `{}`, can \
- only be implemented for a struct/enum type, not `{}`",
- tcx.def_path_str(trait_def_id),
- self_ty
- ),
- "can't implement cross-crate trait with a default impl for \
- non-struct/enum type",
- )),
- } {
- let sp = tcx.def_span(def_id);
- let reported =
- struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
- return Err(reported);
+ match nonlocal_impl {
+ NonlocalImpl::Allow => {}
+ NonlocalImpl::DisallowBecauseNonlocal => {
+ return Err(tcx.sess.emit_err(errors::CrossCrateTraitsDefined {
+ span: tcx.def_span(def_id),
+ traits: tcx.def_path_str(trait_def_id),
+ }));
+ }
+ NonlocalImpl::DisallowOther => {
+ return Err(tcx.sess.emit_err(errors::CrossCrateTraits {
+ span: tcx.def_span(def_id),
+ traits: tcx.def_path_str(trait_def_id),
+ self_ty,
+ }));
+ }
}
}
}
@@ -322,19 +304,18 @@ fn emit_orphan_check_error<'tcx>(
let self_ty = trait_ref.self_ty();
Err(match err {
traits::OrphanCheckErr::NonLocalInputType(tys) => {
- let msg = match self_ty.kind() {
- ty::Adt(..) => "can be implemented for types defined outside of the crate",
- _ if self_ty.is_primitive() => "can be implemented for primitive types",
- _ => "can be implemented for arbitrary types",
- };
- let mut err = struct_span_err!(
- tcx.sess,
- sp,
- E0117,
- "only traits defined in the current crate {msg}"
- );
- err.span_label(sp, "impl doesn't use only types from inside the current crate");
+ let (mut opaque, mut foreign, mut name, mut pointer, mut ty_diag) =
+ (Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new());
+ let mut sugg = None;
for &(mut ty, is_target_ty) in &tys {
+ let span = if is_target_ty {
+ // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
+ self_ty_span
+ } else {
+ // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
+ trait_span
+ };
+
ty = tcx.erase_regions(ty);
ty = match ty.kind() {
// Remove the type arguments from the output, as they are not relevant.
@@ -345,50 +326,103 @@ fn emit_orphan_check_error<'tcx>(
ty::Adt(def, _) => Ty::new_adt(tcx, *def, ty::List::empty()),
_ => ty,
};
- let msg = |ty: &str, postfix: &str| {
- format!("{ty} is not defined in the current crate{postfix}")
- };
- let this = |name: &str| {
- if !trait_ref.def_id.is_local() && !is_target_ty {
- msg("this", " because this is a foreign trait")
+ fn push_to_foreign_or_name<'tcx>(
+ is_foreign: bool,
+ foreign: &mut Vec<errors::OnlyCurrentTraitsForeign>,
+ name: &mut Vec<errors::OnlyCurrentTraitsName<'tcx>>,
+ span: Span,
+ sname: &'tcx str,
+ ) {
+ if is_foreign {
+ foreign.push(errors::OnlyCurrentTraitsForeign { span })
} else {
- msg("this", &format!(" because {name} are always foreign"))
+ name.push(errors::OnlyCurrentTraitsName { span, name: sname });
+ }
+ }
+
+ let is_foreign = !trait_ref.def_id.is_local() && !is_target_ty;
+
+ match &ty.kind() {
+ ty::Slice(_) => {
+ push_to_foreign_or_name(
+ is_foreign,
+ &mut foreign,
+ &mut name,
+ span,
+ "slices",
+ );
+ }
+ ty::Array(..) => {
+ push_to_foreign_or_name(
+ is_foreign,
+ &mut foreign,
+ &mut name,
+ span,
+ "arrays",
+ );
+ }
+ ty::Tuple(..) => {
+ push_to_foreign_or_name(
+ is_foreign,
+ &mut foreign,
+ &mut name,
+ span,
+ "tuples",
+ );
}
- };
- let msg = match &ty.kind() {
- ty::Slice(_) => this("slices"),
- ty::Array(..) => this("arrays"),
- ty::Tuple(..) => this("tuples"),
ty::Alias(ty::Opaque, ..) => {
- "type alias impl trait is treated as if it were foreign, \
- because its hidden type could be from a foreign crate"
- .to_string()
+ opaque.push(errors::OnlyCurrentTraitsOpaque { span })
}
ty::RawPtr(ptr_ty) => {
- emit_newtype_suggestion_for_raw_ptr(
- full_impl_span,
- self_ty,
- self_ty_span,
- ptr_ty,
- &mut err,
- );
-
- msg(&format!("`{ty}`"), " because raw pointers are always foreign")
+ if !self_ty.has_param() {
+ let mut_key = ptr_ty.mutbl.prefix_str();
+ sugg = Some(errors::OnlyCurrentTraitsPointerSugg {
+ wrapper_span: self_ty_span,
+ struct_span: full_impl_span.shrink_to_lo(),
+ mut_key,
+ ptr_ty: ptr_ty.ty,
+ });
+ }
+ pointer.push(errors::OnlyCurrentTraitsPointer { span, pointer: ty });
}
- _ => msg(&format!("`{ty}`"), ""),
- };
-
- if is_target_ty {
- // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
- err.span_label(self_ty_span, msg);
- } else {
- // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
- err.span_label(trait_span, msg);
+ _ => ty_diag.push(errors::OnlyCurrentTraitsTy { span, ty }),
}
}
- err.note("define and implement a trait or new type instead");
- err.emit()
+
+ let err_struct = match self_ty.kind() {
+ ty::Adt(..) => errors::OnlyCurrentTraits::Outside {
+ span: sp,
+ note: (),
+ opaque,
+ foreign,
+ name,
+ pointer,
+ ty: ty_diag,
+ sugg,
+ },
+ _ if self_ty.is_primitive() => errors::OnlyCurrentTraits::Primitive {
+ span: sp,
+ note: (),
+ opaque,
+ foreign,
+ name,
+ pointer,
+ ty: ty_diag,
+ sugg,
+ },
+ _ => errors::OnlyCurrentTraits::Arbitrary {
+ span: sp,
+ note: (),
+ opaque,
+ foreign,
+ name,
+ pointer,
+ ty: ty_diag,
+ sugg,
+ },
+ };
+ tcx.sess.emit_err(err_struct)
}
traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
let mut sp = sp;
@@ -399,85 +433,18 @@ fn emit_orphan_check_error<'tcx>(
}
match local_type {
- Some(local_type) => struct_span_err!(
- tcx.sess,
- sp,
- E0210,
- "type parameter `{}` must be covered by another type \
- when it appears before the first local type (`{}`)",
- param_ty,
- local_type
- )
- .span_label(
- sp,
- format!(
- "type parameter `{param_ty}` must be covered by another type \
- when it appears before the first local type (`{local_type}`)"
- ),
- )
- .note(
- "implementing a foreign trait is only possible if at \
- least one of the types for which it is implemented is local, \
- and no uncovered type parameters appear before that first \
- local type",
- )
- .note(
- "in this case, 'before' refers to the following order: \
- `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \
- where `T0` is the first and `Tn` is the last",
- )
- .emit(),
- None => struct_span_err!(
- tcx.sess,
- sp,
- E0210,
- "type parameter `{}` must be used as the type parameter for some \
- local type (e.g., `MyStruct<{}>`)",
+ Some(local_type) => tcx.sess.emit_err(errors::TyParamFirstLocal {
+ span: sp,
+ note: (),
param_ty,
- param_ty
- )
- .span_label(
- sp,
- format!(
- "type parameter `{param_ty}` must be used as the type parameter for some \
- local type",
- ),
- )
- .note(
- "implementing a foreign trait is only possible if at \
- least one of the types for which it is implemented is local",
- )
- .note(
- "only traits defined in the current crate can be \
- implemented for a type parameter",
- )
- .emit(),
+ local_type,
+ }),
+ None => tcx.sess.emit_err(errors::TyParamSome { span: sp, note: (), param_ty }),
}
}
})
}
-fn emit_newtype_suggestion_for_raw_ptr(
- full_impl_span: Span,
- self_ty: Ty<'_>,
- self_ty_span: Span,
- ptr_ty: &ty::TypeAndMut<'_>,
- diag: &mut Diagnostic,
-) {
- if !self_ty.has_param() {
- let mut_key = ptr_ty.mutbl.prefix_str();
- let msg_sugg = "consider introducing a new wrapper type".to_owned();
- let sugg = vec![
- (
- full_impl_span.shrink_to_lo(),
- format!("struct WrapperType(*{}{});\n\n", mut_key, ptr_ty.ty),
- ),
- (self_ty_span, "WrapperType".to_owned()),
- ];
- diag.multipart_suggestion(msg_sugg, sugg, rustc_errors::Applicability::MaybeIncorrect);
- }
-}
-
/// Lint impls of auto traits if they are likely to have
/// unsound or surprising effects on auto impls.
fn lint_auto_trait_impl<'tcx>(
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 221df4e36..9636c6144 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -14,14 +14,11 @@
//! At present, however, we do run collection across all items in the
//! crate as a kind of pass. This should eventually be factored away.
-use crate::astconv::AstConv;
-use crate::check::intrinsic::intrinsic_operation_unsafety;
-use crate::errors;
-use hir::def::DefKind;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericParamKind, Node};
@@ -40,6 +37,11 @@ use rustc_trait_selection::traits::ObligationCtxt;
use std::iter;
use std::ops::Bound;
+use crate::astconv::AstConv;
+use crate::check::intrinsic::intrinsic_operation_unsafety;
+use crate::errors;
+pub use type_of::test_opaque_hidden_types;
+
mod generics_of;
mod item_bounds;
mod predicates_of;
@@ -76,7 +78,7 @@ pub fn provide(providers: &mut Providers) {
fn_sig,
impl_trait_ref,
impl_polarity,
- generator_kind,
+ coroutine_kind,
collect_mod_item_types,
is_type_alias_impl_trait,
..*providers
@@ -212,7 +214,9 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(
let mut is_fn = false;
let mut is_const_or_static = false;
- if let Some(hir_ty) = hir_ty && let hir::TyKind::BareFn(_) = hir_ty.kind {
+ if let Some(hir_ty) = hir_ty
+ && let hir::TyKind::BareFn(_) = hir_ty.kind
+ {
is_fn = true;
// Check if parent is const or static
@@ -224,10 +228,8 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(
Node::Item(&hir::Item {
kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..),
..
- }) | Node::TraitItem(&hir::TraitItem {
- kind: hir::TraitItemKind::Const(..),
- ..
- }) | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
+ }) | Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Const(..), .. })
+ | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
);
}
@@ -1004,10 +1006,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
&& let Some(lit) = meta.name_value_literal()
{
if seen_attr {
- tcx.sess.span_err(
- meta.span,
- "duplicated `implement_via_object` meta item",
- );
+ tcx.sess.span_err(meta.span, "duplicated `implement_via_object` meta item");
}
seen_attr = true;
@@ -1021,7 +1020,10 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
_ => {
tcx.sess.span_err(
meta.span,
- format!("unknown literal passed to `implement_via_object` attribute: {}", lit.symbol),
+ format!(
+ "unknown literal passed to `implement_via_object` attribute: {}",
+ lit.symbol
+ ),
);
}
}
@@ -1115,8 +1117,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
// Do not try to infer the return type for a impl method coming from a trait
- if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
- tcx.hir().get_parent(hir_id)
+ if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) = tcx.hir().get_parent(hir_id)
&& i.of_trait.is_some()
{
icx.astconv().ty_of_fn(
@@ -1343,7 +1344,13 @@ fn suggest_impl_trait<'tcx>(
if ocx.select_where_possible().is_empty()
&& let item_ty = infcx.resolve_vars_if_possible(item_ty)
&& let Some(item_ty) = item_ty.make_suggestable(tcx, false)
- && let Some(sugg) = formatter(tcx, infcx.resolve_vars_if_possible(args), trait_def_id, assoc_item_def_id, item_ty)
+ && let Some(sugg) = formatter(
+ tcx,
+ infcx.resolve_vars_if_possible(args),
+ trait_def_id,
+ assoc_item_def_id,
+ item_ty,
+ )
{
return Some(sugg);
}
@@ -1543,12 +1550,12 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
fty
}
-fn generator_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::GeneratorKind> {
+fn coroutine_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::CoroutineKind> {
match tcx.hir().get_by_def_id(def_id) {
Node::Expr(&rustc_hir::Expr {
kind: rustc_hir::ExprKind::Closure(&rustc_hir::Closure { body, .. }),
..
- }) => tcx.hir().body(body).generator_kind(),
+ }) => tcx.hir().body(body).coroutine_kind(),
_ => None,
}
}
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 4b7743fae..d746e6dea 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -169,8 +169,8 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTyToOpaque<'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Alias(ty::Projection, projection_ty) = ty.kind()
- && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. })
- = self.tcx.opt_rpitit_info(projection_ty.def_id)
+ && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) =
+ self.tcx.opt_rpitit_info(projection_ty.def_id)
&& fn_def_id == self.fn_def_id
{
self.tcx.type_of(projection_ty.def_id).instantiate(self.tcx, projection_ty.args)
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 1298c0860..104da581e 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -11,7 +11,7 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, ToPredicate};
use rustc_span::symbol::Ident;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{sym, Span, DUMMY_SP};
/// Returns a list of all type predicates (explicit and implicit) for the definition with
/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
@@ -38,11 +38,38 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic
// an obligation and instead be skipped. Otherwise we'd use
// `tcx.def_span(def_id);`
let span = rustc_span::DUMMY_SP;
- result.predicates =
- tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
- ty::TraitRef::identity(tcx, def_id).to_predicate(tcx),
+ let non_const_bound = if tcx.features().effects && tcx.has_attr(def_id, sym::const_trait) {
+ // when `Self` is a const trait, also add `Self: Trait<.., true>` as implied bound,
+ // because only implementing `Self: Trait<.., false>` is currently not possible.
+ Some((
+ ty::TraitRef::new(
+ tcx,
+ def_id,
+ ty::GenericArgs::for_item(tcx, def_id, |param, _| {
+ if param.is_host_effect() {
+ tcx.consts.true_.into()
+ } else {
+ tcx.mk_param_from_def(param)
+ }
+ }),
+ )
+ .to_predicate(tcx),
span,
- ))));
+ ))
+ } else {
+ None
+ };
+ result.predicates = tcx.arena.alloc_from_iter(
+ result
+ .predicates
+ .iter()
+ .copied()
+ .chain(std::iter::once((
+ ty::TraitRef::identity(tcx, def_id).to_predicate(tcx),
+ span,
+ )))
+ .chain(non_const_bound),
+ );
}
debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
result
@@ -180,7 +207,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
//
// default impl Foo for Bar { .. }
//
- // we add a default where clause `Foo: Bar`. We do a similar thing for traits
+ // we add a default where clause `Bar: Foo`. We do a similar thing for traits
// (see below). Recall that a default impl is not itself an impl, but rather a
// set of defaults that can be incorporated into another impl.
if let Some(trait_ref) = is_default_impl_trait {
@@ -389,7 +416,9 @@ fn const_evaluatable_predicates_of(
let node = tcx.hir().get(hir_id);
let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
- if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(impl_) = item.kind {
+ if let hir::Node::Item(item) = node
+ && let hir::ItemKind::Impl(impl_) = item.kind
+ {
if let Some(of_trait) = &impl_.of_trait {
debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
collector.visit_trait_ref(of_trait);
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index eb4466449..6424d1c79 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -880,7 +880,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
(pair, r)
})
.unzip();
- self.record_late_bound_vars(hir_id, binders.clone());
+ self.record_late_bound_vars(hir_id, binders);
// Even if there are no lifetimes defined here, we still wrap it in a binder
// scope. If there happens to be a nested poly trait ref (an error), that
// will be `Concatenating` anyways, so we don't have to worry about the depth
@@ -1190,7 +1190,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
Scope::Root { opt_parent_item } => {
if let Some(parent_item) = opt_parent_item
&& let parent_generics = self.tcx.generics_of(parent_item)
- && parent_generics.param_def_id_to_index(self.tcx, region_def_id.to_def_id()).is_some()
+ && parent_generics
+ .param_def_id_to_index(self.tcx, region_def_id.to_def_id())
+ .is_some()
{
break Some(ResolvedArg::EarlyBound(region_def_id.to_def_id()));
}
@@ -1209,13 +1211,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
// regular fns.
if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
&& let hir::LifetimeName::Param(param_id) = lifetime_ref.res
- && let Some(generics) = self.tcx.hir().get_generics(self.tcx.local_parent(param_id))
+ && let Some(generics) =
+ self.tcx.hir().get_generics(self.tcx.local_parent(param_id))
&& let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
&& param.is_elided_lifetime()
&& !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async()
&& !self.tcx.features().anonymous_lifetime_in_impl_trait
{
- let mut diag = rustc_session::parse::feature_err(
+ let mut diag = rustc_session::parse::feature_err(
&self.tcx.sess.parse_sess,
sym::anonymous_lifetime_in_impl_trait,
lifetime_ref.ident.span,
@@ -1225,25 +1228,31 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
if let Some(generics) =
self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id)
{
- let new_param_sugg = if let Some(span) =
- generics.span_for_lifetime_suggestion()
- {
- (span, "'a, ".to_owned())
- } else {
- (generics.span, "<'a>".to_owned())
- };
+ let new_param_sugg =
+ if let Some(span) = generics.span_for_lifetime_suggestion() {
+ (span, "'a, ".to_owned())
+ } else {
+ (generics.span, "<'a>".to_owned())
+ };
let lifetime_sugg = match lifetime_ref.suggestion_position() {
- (hir::LifetimeSuggestionPosition::Normal, span) => (span, "'a".to_owned()),
- (hir::LifetimeSuggestionPosition::Ampersand, span) => (span, "'a ".to_owned()),
- (hir::LifetimeSuggestionPosition::ElidedPath, span) => (span, "<'a>".to_owned()),
- (hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => (span, "'a, ".to_owned()),
- (hir::LifetimeSuggestionPosition::ObjectDefault, span) => (span, "+ 'a".to_owned()),
+ (hir::LifetimeSuggestionPosition::Normal, span) => {
+ (span, "'a".to_owned())
+ }
+ (hir::LifetimeSuggestionPosition::Ampersand, span) => {
+ (span, "'a ".to_owned())
+ }
+ (hir::LifetimeSuggestionPosition::ElidedPath, span) => {
+ (span, "<'a>".to_owned())
+ }
+ (hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => {
+ (span, "'a, ".to_owned())
+ }
+ (hir::LifetimeSuggestionPosition::ObjectDefault, span) => {
+ (span, "+ 'a".to_owned())
+ }
};
- let suggestions = vec![
- lifetime_sugg,
- new_param_sugg,
- ];
+ let suggestions = vec![lifetime_sugg, new_param_sugg];
diag.span_label(
lifetime_ref.ident.span,
@@ -1378,7 +1387,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
Scope::Root { opt_parent_item } => {
if let Some(parent_item) = opt_parent_item
&& let parent_generics = self.tcx.generics_of(parent_item)
- && parent_generics.param_def_id_to_index(self.tcx, param_def_id.to_def_id()).is_some()
+ && parent_generics
+ .param_def_id_to_index(self.tcx, param_def_id.to_def_id())
+ .is_some()
{
break Some(ResolvedArg::EarlyBound(param_def_id.to_def_id()));
}
@@ -1689,14 +1700,12 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
let bound_vars = if let Some(type_def_id) = type_def_id
&& self.tcx.def_kind(type_def_id) == DefKind::Trait
- && let Some((mut bound_vars, assoc_fn)) =
- BoundVarContext::supertrait_hrtb_vars(
- self.tcx,
- type_def_id,
- binding.ident,
- ty::AssocKind::Fn,
- )
- {
+ && let Some((mut bound_vars, assoc_fn)) = BoundVarContext::supertrait_hrtb_vars(
+ self.tcx,
+ type_def_id,
+ binding.ident,
+ ty::AssocKind::Fn,
+ ) {
bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).params.iter().map(
|param| match param.kind {
ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
@@ -1708,14 +1717,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
},
));
- bound_vars
- .extend(self.tcx.fn_sig(assoc_fn.def_id).instantiate_identity().bound_vars());
+ bound_vars.extend(
+ self.tcx.fn_sig(assoc_fn.def_id).instantiate_identity().bound_vars(),
+ );
bound_vars
} else {
- self.tcx.sess.delay_span_bug(
- binding.ident.span,
- "bad return type notation here",
- );
+ self.tcx
+ .sess
+ .delay_span_bug(binding.ident.span, "bad return type notation here");
vec![]
};
self.with(scope, |this| {
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index ae62119b1..d7bd2a7b1 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -11,6 +11,7 @@ use rustc_span::{Span, DUMMY_SP};
use super::ItemCtxt;
use super::{bad_placeholder, is_suggestable_infer_ty};
+pub use opaque::test_opaque_hidden_types;
mod opaque;
@@ -30,10 +31,10 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
| Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
if constant.hir_id() == hir_id =>
{
- return tcx.types.usize
+ return tcx.types.usize;
}
Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => {
- return tcx.typeck(def_id).node_type(e.hir_id)
+ return tcx.typeck(def_id).node_type(e.hir_id);
}
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
@@ -43,36 +44,38 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
_ => false,
}) =>
{
- return tcx.typeck(def_id).node_type(hir_id)
+ return tcx.typeck(def_id).node_type(hir_id);
}
Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
- return tcx
- .adt_def(tcx.hir().get_parent_item(hir_id))
- .repr()
- .discr_type()
- .to_ty(tcx)
+ return tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx);
}
Node::GenericParam(&GenericParam {
def_id: param_def_id,
kind: GenericParamKind::Const { default: Some(ct), .. },
..
}) if ct.hir_id == hir_id => {
- return tcx.type_of(param_def_id)
+ return tcx
+ .type_of(param_def_id)
.no_bound_vars()
- .expect("const parameter types cannot be generic")
+ .expect("const parameter types cannot be generic");
}
- Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. })
- if let Node::TraitRef(trait_ref) = tcx.hir().get(
- tcx.hir().parent_id(binding_id)
- ) =>
+ Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. })
+ if let Node::TraitRef(trait_ref) = tcx.hir().get(tcx.hir().parent_id(binding_id)) =>
{
let Some(trait_def_id) = trait_ref.trait_def_id() else {
- return Ty::new_error_with_message(tcx,tcx.def_span(def_id), "Could not find trait");
+ return Ty::new_error_with_message(
+ tcx,
+ tcx.def_span(def_id),
+ "Could not find trait",
+ );
};
let assoc_items = tcx.associated_items(trait_def_id);
let assoc_item = assoc_items.find_by_name_and_kind(
- tcx, binding.ident, ty::AssocKind::Const, def_id.to_def_id(),
+ tcx,
+ binding.ident,
+ ty::AssocKind::Const,
+ def_id.to_def_id(),
);
return if let Some(assoc_item) = assoc_item {
tcx.type_of(assoc_item.def_id)
@@ -80,8 +83,12 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
.expect("const parameter types cannot be generic")
} else {
// FIXME(associated_const_equality): add a useful error message here.
- Ty::new_error_with_message(tcx,tcx.def_span(def_id), "Could not find associated const on trait")
- }
+ Ty::new_error_with_message(
+ tcx,
+ tcx.def_span(def_id),
+ "Could not find associated const on trait",
+ )
+ };
}
// This match arm is for when the def_id appears in a GAT whose
@@ -138,7 +145,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
(generics, arg_index)
} else {
// I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
- return Ty::new_error_with_message(tcx,
+ return Ty::new_error_with_message(
+ tcx,
tcx.def_span(def_id),
"unexpected non-GAT usage of an anon const",
);
@@ -155,7 +163,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
// As there is no relevant param for `def_id`, we simply return
// `None` here.
let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else {
- return Ty::new_error_with_message(tcx,
+ return Ty::new_error_with_message(
+ tcx,
tcx.def_span(def_id),
format!("unable to find type-dependent def for {parent_node_id:?}"),
);
@@ -196,14 +205,16 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
path
} else {
- return Ty::new_error_with_message(tcx,
+ return Ty::new_error_with_message(
+ tcx,
tcx.def_span(def_id),
format!("unable to find const parent for {hir_id} in pat {pat:?}"),
);
}
}
_ => {
- return Ty::new_error_with_message(tcx,
+ return Ty::new_error_with_message(
+ tcx,
tcx.def_span(def_id),
format!("unexpected const parent path {parent_node:?}"),
);
@@ -216,16 +227,20 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
let Some((arg_index, segment)) = path.segments.iter().find_map(|seg| {
let args = seg.args?;
args.args
- .iter()
- .filter(|arg| arg.is_ty_or_const())
- .position(|arg| arg.hir_id() == hir_id)
- .map(|index| (index, seg)).or_else(|| args.bindings
.iter()
- .filter_map(TypeBinding::opt_const)
- .position(|ct| ct.hir_id == hir_id)
- .map(|idx| (idx, seg)))
+ .filter(|arg| arg.is_ty_or_const())
+ .position(|arg| arg.hir_id() == hir_id)
+ .map(|index| (index, seg))
+ .or_else(|| {
+ args.bindings
+ .iter()
+ .filter_map(TypeBinding::opt_const)
+ .position(|ct| ct.hir_id == hir_id)
+ .map(|idx| (idx, seg))
+ })
}) else {
- return Ty::new_error_with_message(tcx,
+ return Ty::new_error_with_message(
+ tcx,
tcx.def_span(def_id),
"no arg matching AnonConst in path",
);
@@ -234,7 +249,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
let generics = match tcx.res_generics_def_id(segment.res) {
Some(def_id) => tcx.generics_of(def_id),
None => {
- return Ty::new_error_with_message(tcx,
+ return Ty::new_error_with_message(
+ tcx,
tcx.def_span(def_id),
format!("unexpected anon const res {:?} in path: {:?}", segment.res, path),
);
@@ -244,10 +260,13 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
(generics, arg_index)
}
- _ => return Ty::new_error_with_message(tcx,
- tcx.def_span(def_id),
- format!("unexpected const parent in type_of(): {parent_node:?}"),
- ),
+ _ => {
+ return Ty::new_error_with_message(
+ tcx,
+ tcx.def_span(def_id),
+ format!("unexpected const parent in type_of(): {parent_node:?}"),
+ );
+ }
};
debug!(?parent_node);
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index 0544c5ca8..e8ab2651d 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -1,12 +1,25 @@
use rustc_errors::StashKey;
-use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_span::DUMMY_SP;
+use rustc_span::{sym, DUMMY_SP};
-use crate::errors::{TaitForwardCompat, UnconstrainedOpaqueType};
+use crate::errors::{TaitForwardCompat, TypeOf, UnconstrainedOpaqueType};
+
+pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) {
+ if tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) {
+ for id in tcx.hir().items() {
+ if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) {
+ let type_of = tcx.type_of(id.owner_id).instantiate_identity();
+
+ tcx.sess.emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of });
+ }
+ }
+ }
+}
/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
/// laid for "higher-order pattern unification".
@@ -170,9 +183,17 @@ impl TaitConstraintLocator<'_> {
};
// Use borrowck to get the type with unerased regions.
- let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types;
- debug!(?concrete_opaque_types);
- if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) {
+ let borrowck_results = &self.tcx.mir_borrowck(item_def_id);
+
+ // If the body was tainted, then assume the opaque may have been constrained and just set it to error.
+ if let Some(guar) = borrowck_results.tainted_by_errors {
+ self.found =
+ Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) });
+ return;
+ }
+
+ debug!(?borrowck_results.concrete_opaque_types);
+ if let Some(&concrete_type) = borrowck_results.concrete_opaque_types.get(&self.def_id) {
debug!(?concrete_type, "found constraint");
if let Some(prev) = &mut self.found {
if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index 5591fa6f2..ed5e9dd2b 100644
--- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -1,7 +1,7 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use std::ops::ControlFlow;
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 0efe82b20..dd83b5b6f 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -96,7 +96,7 @@ pub struct CopyImplOnTypeWithDtor {
#[diag(hir_analysis_multiple_relaxed_default_bounds, code = "E0203")]
pub struct MultipleRelaxedDefaultBounds {
#[primary_span]
- pub span: Span,
+ pub spans: Vec<Span>,
}
#[derive(Diagnostic)]
@@ -226,7 +226,9 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
let mut suggested = false;
// Don't suggest setting the type params if there are some already: the order is
// tricky to get right and the user will already know what the syntax is.
- if let Some(snippet) = self.span_snippet && self.empty_generic_args {
+ if let Some(snippet) = self.span_snippet
+ && self.empty_generic_args
+ {
if snippet.ends_with('>') {
// The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion
// we would have to preserve the right order. For now, as clearly the user is
@@ -466,6 +468,14 @@ pub(crate) struct VariancesOf {
}
#[derive(Diagnostic)]
+#[diag(hir_analysis_type_of)]
+pub(crate) struct TypeOf<'tcx> {
+ #[primary_span]
+ pub span: Span,
+ pub type_of: Ty<'tcx>,
+}
+
+#[derive(Diagnostic)]
#[diag(hir_analysis_pass_to_variadic_function, code = "E0617")]
pub(crate) struct PassToVariadicFunction<'tcx, 'a> {
#[primary_span]
@@ -673,7 +683,6 @@ pub(crate) struct SIMDFFIHighlyExperimental {
}
#[derive(Diagnostic)]
-
pub enum ImplNotMarkedDefault {
#[diag(hir_analysis_impl_not_marked_default, code = "E0520")]
#[note]
@@ -1149,3 +1158,174 @@ pub struct ImplForTyRequires {
pub trait_name: String,
pub ty: String,
}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_traits_with_defualt_impl, code = "E0321")]
+#[note]
+pub struct TraitsWithDefaultImpl<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub traits: String,
+ pub problematic_kind: &'a str,
+ pub self_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_cross_crate_traits, code = "E0321")]
+pub struct CrossCrateTraits<'a> {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub traits: String,
+ pub self_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_cross_crate_traits_defined, code = "E0321")]
+pub struct CrossCrateTraitsDefined {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub traits: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_ty_param_first_local, code = "E0210")]
+#[note]
+pub struct TyParamFirstLocal<'a> {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[note(hir_analysis_case_note)]
+ pub note: (),
+ pub param_ty: Ty<'a>,
+ pub local_type: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_ty_param_some, code = "E0210")]
+#[note]
+pub struct TyParamSome<'a> {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[note(hir_analysis_only_note)]
+ pub note: (),
+ pub param_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+pub enum OnlyCurrentTraits<'a> {
+ #[diag(hir_analysis_only_current_traits_outside, code = "E0117")]
+ Outside {
+ #[primary_span]
+ #[label(hir_analysis_only_current_traits_label)]
+ span: Span,
+ #[note(hir_analysis_only_current_traits_note)]
+ note: (),
+ #[subdiagnostic]
+ opaque: Vec<OnlyCurrentTraitsOpaque>,
+ #[subdiagnostic]
+ foreign: Vec<OnlyCurrentTraitsForeign>,
+ #[subdiagnostic]
+ name: Vec<OnlyCurrentTraitsName<'a>>,
+ #[subdiagnostic]
+ pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
+ #[subdiagnostic]
+ ty: Vec<OnlyCurrentTraitsTy<'a>>,
+ #[subdiagnostic]
+ sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
+ },
+ #[diag(hir_analysis_only_current_traits_primitive, code = "E0117")]
+ Primitive {
+ #[primary_span]
+ #[label(hir_analysis_only_current_traits_label)]
+ span: Span,
+ #[note(hir_analysis_only_current_traits_note)]
+ note: (),
+ #[subdiagnostic]
+ opaque: Vec<OnlyCurrentTraitsOpaque>,
+ #[subdiagnostic]
+ foreign: Vec<OnlyCurrentTraitsForeign>,
+ #[subdiagnostic]
+ name: Vec<OnlyCurrentTraitsName<'a>>,
+ #[subdiagnostic]
+ pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
+ #[subdiagnostic]
+ ty: Vec<OnlyCurrentTraitsTy<'a>>,
+ #[subdiagnostic]
+ sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
+ },
+ #[diag(hir_analysis_only_current_traits_arbitrary, code = "E0117")]
+ Arbitrary {
+ #[primary_span]
+ #[label(hir_analysis_only_current_traits_label)]
+ span: Span,
+ #[note(hir_analysis_only_current_traits_note)]
+ note: (),
+ #[subdiagnostic]
+ opaque: Vec<OnlyCurrentTraitsOpaque>,
+ #[subdiagnostic]
+ foreign: Vec<OnlyCurrentTraitsForeign>,
+ #[subdiagnostic]
+ name: Vec<OnlyCurrentTraitsName<'a>>,
+ #[subdiagnostic]
+ pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
+ #[subdiagnostic]
+ ty: Vec<OnlyCurrentTraitsTy<'a>>,
+ #[subdiagnostic]
+ sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
+ },
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_only_current_traits_opaque)]
+pub struct OnlyCurrentTraitsOpaque {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_only_current_traits_foreign)]
+pub struct OnlyCurrentTraitsForeign {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_only_current_traits_name)]
+pub struct OnlyCurrentTraitsName<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: &'a str,
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_only_current_traits_pointer)]
+pub struct OnlyCurrentTraitsPointer<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub pointer: Ty<'a>,
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_only_current_traits_ty)]
+pub struct OnlyCurrentTraitsTy<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub ty: Ty<'a>,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+ hir_analysis_only_current_traits_pointer_sugg,
+ applicability = "maybe-incorrect"
+)]
+pub struct OnlyCurrentTraitsPointerSugg<'a> {
+ #[suggestion_part(code = "WrapperType")]
+ pub wrapper_span: Span,
+ #[suggestion_part(code = "struct WrapperType(*{mut_key}{ptr_ty});\n\n")]
+ pub struct_span: Span,
+ pub mut_key: &'a str,
+ pub ptr_ty: Ty<'a>,
+}
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 3760195a5..7941861fd 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -131,7 +131,9 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
}
fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) {
- if let Node::Impl(impl2_id) = impl2_node && tcx.associated_item_def_ids(impl1_def_id).is_empty() {
+ if let Node::Impl(impl2_id) = impl2_node
+ && tcx.associated_item_def_ids(impl1_def_id).is_empty()
+ {
let base_impl_span = tcx.def_span(impl2_id);
tcx.sess.emit_err(errors::EmptySpecialization { span, base_impl_span });
}
@@ -196,7 +198,7 @@ fn get_impl_args(
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let guar = ocx.infcx.err_ctxt().report_fulfillment_errors(&errors);
+ let guar = ocx.infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(guar);
}
@@ -376,9 +378,9 @@ fn check_predicates<'tcx>(
let always_applicable_traits = impl1_predicates
.iter()
.copied()
- .filter(|(clause, _span)| {
+ .filter(|&(clause, _span)| {
matches!(
- trait_predicate_kind(tcx, clause.as_predicate()),
+ trait_specialization_kind(tcx, clause),
Some(TraitSpecializationKind::AlwaysApplicable)
)
})
@@ -402,7 +404,7 @@ fn check_predicates<'tcx>(
.iter()
.any(|pred2| trait_predicates_eq(tcx, clause.as_predicate(), *pred2, span))
{
- check_specialization_on(tcx, clause.as_predicate(), span)
+ check_specialization_on(tcx, clause, span)
}
}
}
@@ -441,19 +443,16 @@ fn trait_predicates_eq<'tcx>(
}
#[instrument(level = "debug", skip(tcx))]
-fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>, span: Span) {
- match predicate.kind().skip_binder() {
+fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, span: Span) {
+ match clause.kind().skip_binder() {
// Global predicates are either always true or always false, so we
// are fine to specialize on.
- _ if predicate.is_global() => (),
+ _ if clause.is_global() => (),
// We allow specializing on explicitly marked traits with no associated
// items.
- ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
- trait_ref,
- polarity: _,
- })) => {
+ ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => {
if !matches!(
- trait_predicate_kind(tcx, predicate),
+ trait_specialization_kind(tcx, clause),
Some(TraitSpecializationKind::Marker)
) {
tcx.sess
@@ -467,10 +466,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
.emit();
}
}
- ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
- projection_ty,
- term,
- })) => {
+ ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
tcx.sess
.struct_span_err(
span,
@@ -478,7 +474,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
)
.emit();
}
- ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => {
+ ty::ClauseKind::ConstArgHasType(..) => {
// FIXME(min_specialization), FIXME(const_generics):
// It probably isn't right to allow _every_ `ConstArgHasType` but I am somewhat unsure
// about the actual rules that would be sound. Can't just always error here because otherwise
@@ -490,33 +486,25 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
}
_ => {
tcx.sess
- .struct_span_err(span, format!("cannot specialize on predicate `{predicate}`"))
+ .struct_span_err(span, format!("cannot specialize on predicate `{clause}`"))
.emit();
}
}
}
-fn trait_predicate_kind<'tcx>(
+fn trait_specialization_kind<'tcx>(
tcx: TyCtxt<'tcx>,
- predicate: ty::Predicate<'tcx>,
+ clause: ty::Clause<'tcx>,
) -> Option<TraitSpecializationKind> {
- match predicate.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
- trait_ref,
- polarity: _,
- })) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
- ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_))
- | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_))
- | ty::PredicateKind::Clause(ty::ClauseKind::Projection(_))
- | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
- | ty::PredicateKind::AliasRelate(..)
- | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_))
- | ty::PredicateKind::Subtype(_)
- | ty::PredicateKind::Coerce(_)
- | ty::PredicateKind::ObjectSafe(_)
- | ty::PredicateKind::ClosureKind(..)
- | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
- | ty::PredicateKind::ConstEquate(..)
- | ty::PredicateKind::Ambiguous => None,
+ match clause.kind().skip_binder() {
+ ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => {
+ Some(tcx.trait_def(trait_ref.def_id).specialization_kind)
+ }
+ ty::ClauseKind::RegionOutlives(_)
+ | ty::ClauseKind::TypeOutlives(_)
+ | ty::ClauseKind::Projection(_)
+ | ty::ClauseKind::ConstArgHasType(..)
+ | ty::ClauseKind::WellFormed(_)
+ | ty::ClauseKind::ConstEvaluatable(..) => None,
}
}
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 03963925d..2b8219c01 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -57,6 +57,9 @@ This API is completely unstable and subject to change.
#![allow(rustc::potential_query_instability)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
#![feature(if_let_guard)]
@@ -179,13 +182,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
}
tcx.sess.track_errors(|| {
- tcx.sess.time("impl_wf_inference", || {
- tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module))
- });
- })?;
-
- tcx.sess.track_errors(|| {
tcx.sess.time("coherence_checking", || {
+ // Check impls constrain their parameters
+ tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module));
+
for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
tcx.ensure().coherent_trait(trait_def_id);
}
@@ -202,17 +202,23 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
})?;
}
- tcx.sess.track_errors(|| {
- tcx.sess.time("wf_checking", || {
- tcx.hir().par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module))
- });
- })?;
+ let errs = tcx.sess.time("wf_checking", || {
+ tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module))
+ });
// NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync.
tcx.sess.time("item_types_checking", || {
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
});
+ // HACK: `check_mod_type_wf` may spuriously emit errors due to `delay_span_bug`, even if those errors
+ // only actually get emitted in `check_mod_item_types`.
+ errs?;
+
+ if tcx.features().rustc_attrs {
+ tcx.sess.track_errors(|| collect::test_opaque_hidden_types(tcx))?;
+ }
+
// Freeze definitions as we don't add new ones at this point. This improves performance by
// allowing lock-free access to them.
tcx.untracked().definitions.freeze();
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
index 61b182b1b..76bd370a6 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
@@ -129,6 +129,44 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
if self.missing_lifetimes() { "lifetime" } else { "generic" }
}
+ /// Returns true if the generic type is a trait
+ /// and is being referred to from one of its trait impls
+ fn is_in_trait_impl(&self) -> bool {
+ if self.tcx.is_trait(self.def_id) {
+ // Here we check if the reference to the generic type
+ // is from the 'of_trait' field of the enclosing impl
+
+ let parent = self.tcx.hir().get_parent(self.path_segment.hir_id);
+ let parent_item = self
+ .tcx
+ .hir()
+ .get_by_def_id(self.tcx.hir().get_parent_item(self.path_segment.hir_id).def_id);
+
+ // Get the HIR id of the trait ref
+ let hir::Node::TraitRef(hir::TraitRef { hir_ref_id: trait_ref_id, .. }) = parent else {
+ return false;
+ };
+
+ // Get the HIR id of the 'of_trait' field of the impl
+ let hir::Node::Item(hir::Item {
+ kind:
+ hir::ItemKind::Impl(hir::Impl {
+ of_trait: Some(hir::TraitRef { hir_ref_id: id_in_of_trait, .. }),
+ ..
+ }),
+ ..
+ }) = parent_item
+ else {
+ return false;
+ };
+
+ // Check that trait is referred to from the of_trait field of impl
+ trait_ref_id == id_in_of_trait
+ } else {
+ false
+ }
+ }
+
fn num_provided_args(&self) -> usize {
if self.missing_lifetimes() {
self.num_provided_lifetime_args()
@@ -316,12 +354,18 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
}
// Suggest `'_` when in function parameter or elided function return.
- if let Some(fn_decl) = node.fn_decl() && let Some(ty_id) = ty_id {
+ if let Some(fn_decl) = node.fn_decl()
+ && let Some(ty_id) = ty_id
+ {
let in_arg = fn_decl.inputs.iter().any(|t| t.hir_id == ty_id);
- let in_ret = matches!(fn_decl.output, hir::FnRetTy::Return(ty) if ty.hir_id == ty_id);
+ let in_ret =
+ matches!(fn_decl.output, hir::FnRetTy::Return(ty) if ty.hir_id == ty_id);
if in_arg || (in_ret && fn_decl.lifetime_elision_allowed) {
- return std::iter::repeat("'_".to_owned()).take(num_params_to_take).collect::<Vec<_>>().join(", ");
+ return std::iter::repeat("'_".to_owned())
+ .take(num_params_to_take)
+ .collect::<Vec<_>>()
+ .join(", ");
}
}
@@ -730,28 +774,27 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
);
if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id)
- && let Some(parent_node) = self.tcx.hir().find(parent_node)
- && let hir::Node::Expr(expr) = parent_node {
+ && let Some(parent_node) = self.tcx.hir().find(parent_node)
+ && let hir::Node::Expr(expr) = parent_node
+ {
match &expr.kind {
- hir::ExprKind::Path(qpath) => {
- self.suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
+ hir::ExprKind::Path(qpath) => self
+ .suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
err,
qpath,
msg,
num_assoc_fn_excess_args,
- num_trait_generics_except_self
- )
- },
- hir::ExprKind::MethodCall(..) => {
- self.suggest_moving_args_from_assoc_fn_to_trait_for_method_call(
+ num_trait_generics_except_self,
+ ),
+ hir::ExprKind::MethodCall(..) => self
+ .suggest_moving_args_from_assoc_fn_to_trait_for_method_call(
err,
trait_,
expr,
msg,
num_assoc_fn_excess_args,
- num_trait_generics_except_self
- )
- },
+ num_trait_generics_except_self,
+ ),
_ => return,
}
}
@@ -766,23 +809,25 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
num_trait_generics_except_self: usize,
) {
if let hir::QPath::Resolved(_, path) = qpath
- && let Some(trait_path_segment) = path.segments.get(0) {
+ && let Some(trait_path_segment) = path.segments.get(0)
+ {
let num_generic_args_supplied_to_trait = trait_path_segment.args().num_generic_params();
- if num_generic_args_supplied_to_trait + num_assoc_fn_excess_args == num_trait_generics_except_self
+ if num_generic_args_supplied_to_trait + num_assoc_fn_excess_args
+ == num_trait_generics_except_self
{
if let Some(span) = self.gen_args.span_ext()
- && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+ && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
+ {
let sugg = vec![
- (self.path_segment.ident.span, format!("{}::{}", snippet, self.path_segment.ident)),
- (span.with_lo(self.path_segment.ident.span.hi()), "".to_owned())
+ (
+ self.path_segment.ident.span,
+ format!("{}::{}", snippet, self.path_segment.ident),
+ ),
+ (span.with_lo(self.path_segment.ident.span.hi()), "".to_owned()),
];
- err.multipart_suggestion(
- msg,
- sugg,
- Applicability::MaybeIncorrect
- );
+ err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect);
}
}
}
@@ -948,20 +993,26 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
// If there is a single unbound associated type and a single excess generic param
// suggest replacing the generic param with the associated type bound
if provided_args_matches_unbound_traits && !unbound_types.is_empty() {
- let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
- let suggestions = iter::zip(unused_generics, &unbound_types)
- .map(|(potential, name)| (potential.span().shrink_to_lo(), format!("{name} = ")))
- .collect::<Vec<_>>();
-
- if !suggestions.is_empty() {
- err.multipart_suggestion_verbose(
- format!(
- "replace the generic bound{s} with the associated type{s}",
- s = pluralize!(unbound_types.len())
- ),
- suggestions,
- Applicability::MaybeIncorrect,
- );
+ // Don't suggest if we're in a trait impl as
+ // that would result in invalid syntax (fixes #116464)
+ if !self.is_in_trait_impl() {
+ let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
+ let suggestions = iter::zip(unused_generics, &unbound_types)
+ .map(|(potential, name)| {
+ (potential.span().shrink_to_lo(), format!("{name} = "))
+ })
+ .collect::<Vec<_>>();
+
+ if !suggestions.is_empty() {
+ err.multipart_suggestion_verbose(
+ format!(
+ "replace the generic bound{s} with the associated type{s}",
+ s = pluralize!(unbound_types.len())
+ ),
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ }
}
} else if remove_entire_generics {
let span = self
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index 61d9c989e..5f8b1ace6 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -235,7 +235,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
// leaf type -- noop
}
- ty::FnDef(..) | ty::Generator(..) | ty::Closure(..) => {
+ ty::FnDef(..) | ty::Coroutine(..) | ty::Closure(..) => {
bug!("Unexpected closure type in variance computation");
}
@@ -312,7 +312,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
// types, where we use Error as the Self type
}
- ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Bound(..) | ty::Infer(..) => {
+ ty::Placeholder(..) | ty::CoroutineWitness(..) | ty::Bound(..) | ty::Infer(..) => {
bug!("unexpected type encountered in variance inference: {}", ty);
}
}
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 85e0000ab..9fb39a0e9 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -192,5 +192,5 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
}
}
}
- tcx.arena.alloc_from_iter(collector.variances.into_iter())
+ tcx.arena.alloc_from_iter(collector.variances)
}