summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /compiler/rustc_hir_analysis/src
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+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/errors.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/generics.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs240
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs263
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_method.rs576
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs39
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs47
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs220
-rw-r--r--compiler/rustc_hir_analysis/src/check_unused.rs19
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs66
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs59
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs250
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/collect/lifetimes.rs577
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs191
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs18
-rw-r--r--compiler/rustc_hir_analysis/src/constrained_generic_params.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs149
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs52
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/explicit.rs43
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/mod.rs24
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs71
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs131
-rw-r--r--compiler/rustc_hir_analysis/src/variance/terms.rs18
32 files changed, 1772 insertions, 1398 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index a9152bdc5..e6465d641 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -177,11 +177,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.all_traits()
.filter(|trait_def_id| {
let viz = self.tcx().visibility(*trait_def_id);
- if let Some(def_id) = self.item_def_id() {
- viz.is_accessible_from(def_id, self.tcx())
- } else {
- viz.is_visible_locally()
- }
+ let def_id = self.item_def_id();
+ viz.is_accessible_from(def_id, self.tcx())
})
.collect();
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index 47915b4bd..f64d65cc6 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -11,7 +11,6 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::GenericArg;
-use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::ty::{
self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt,
};
@@ -83,9 +82,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Res::Def(DefKind::TyParam, src_def_id) => {
if let Some(param_local_id) = param.def_id.as_local() {
let param_name = tcx.hir().ty_param_name(param_local_id);
- let infcx = tcx.infer_ctxt().build();
- let param_type =
- infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id));
+ let param_type = tcx.type_of(param.def_id);
if param_type.is_suggestable(tcx, false) {
err.span_suggestion(
tcx.def_span(src_def_id),
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 38f195dab..78d204d47 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -23,7 +23,6 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{walk_generics, Visitor as _};
-use rustc_hir::lang_items::LangItem;
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
@@ -55,7 +54,7 @@ pub struct PathSeg(pub DefId, pub usize);
pub trait AstConv<'tcx> {
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
- fn item_def_id(&self) -> Option<DefId>;
+ fn item_def_id(&self) -> DefId;
/// Returns predicates in scope of the form `X: Foo<T>`, where `X`
/// is a type parameter `X` with the given id `def_id` and T
@@ -110,13 +109,16 @@ pub trait AstConv<'tcx> {
) -> Ty<'tcx>;
/// Normalize an associated type coming from the user.
+ ///
+ /// This should only be used by astconv. Use `FnCtxt::normalize`
+ /// or `ObligationCtxt::normalize` in downstream crates.
fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>;
/// Invoked when we encounter an error from some prior pass
/// (e.g., resolve) that is translated into a ty-error. This is
/// used to help suppress derived errors typeck might otherwise
/// report.
- fn set_tainted_by_errors(&self);
+ fn set_tainted_by_errors(&self, e: ErrorGuaranteed);
fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span);
}
@@ -242,14 +244,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
None => {
- self.re_infer(def, lifetime.span).unwrap_or_else(|| {
+ self.re_infer(def, lifetime.ident.span).unwrap_or_else(|| {
debug!(?lifetime, "unelided lifetime in signature");
// This indicates an illegal lifetime
// elision. `resolve_lifetime` should have
// reported an error in this case -- but if
// not, let's error out.
- tcx.sess.delay_span_bug(lifetime.span, "unelided lifetime in signature");
+ tcx.sess.delay_span_bug(lifetime.ident.span, "unelided lifetime in signature");
// Supply some dummy value. We don't have an
// `re_error`, annoyingly, so use `'static`.
@@ -275,7 +277,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
item_segment.args(),
item_segment.infer_args,
None,
- None,
+ ty::BoundConstness::NotConst,
);
if let Some(b) = item_segment.args().bindings.first() {
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
@@ -325,7 +327,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
generic_args: &'a hir::GenericArgs<'_>,
infer_args: bool,
self_ty: Option<Ty<'tcx>>,
- constness: Option<ty::BoundConstness>,
+ constness: ty::BoundConstness,
) -> (SubstsRef<'tcx>, GenericArgCountResult) {
// If the type is parameterized by this region, then replace this
// region with the current anon region binding (in other words,
@@ -345,7 +347,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
assert!(self_ty.is_some());
}
} else {
- assert!(self_ty.is_none() && parent_substs.is_empty());
+ assert!(self_ty.is_none());
}
let arg_count = Self::check_generic_arg_count(
@@ -433,7 +435,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
ty::Const::from_opt_const_arg_anon_const(
tcx,
ty::WithOptConstParam {
- did: tcx.hir().local_def_id(ct.value.hir_id),
+ did: ct.value.def_id,
const_param_did: Some(param.def_id),
},
)
@@ -501,6 +503,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
GenericParamDefKind::Const { has_default } => {
let ty = tcx.at(self.span).type_of(param.def_id);
+ if ty.references_error() {
+ return tcx.const_error(ty).into();
+ }
if !infer_args && has_default {
tcx.bound_const_param_default(param.def_id)
.subst(tcx, substs.unwrap())
@@ -536,7 +541,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&mut substs_ctx,
);
- if let Some(ty::BoundConstness::ConstIfConst) = constness
+ if let ty::BoundConstness::ConstIfConst = constness
&& generics.has_self && !tcx.has_attr(def_id, sym::const_trait)
{
tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span } );
@@ -568,8 +573,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into())
}
hir::Term::Const(ref c) => {
- let local_did = self.tcx().hir().local_def_id(c.hir_id);
- let c = Const::from_anon_const(self.tcx(), local_did);
+ let c = Const::from_anon_const(self.tcx(), c.def_id);
ConvertedBindingKind::Equality(c.into())
}
},
@@ -609,7 +613,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
item_segment.args(),
item_segment.infer_args,
None,
- None,
+ ty::BoundConstness::NotConst,
);
if let Some(b) = item_segment.args().bindings.first() {
@@ -639,7 +643,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty,
trait_ref.path.segments.last().unwrap(),
true,
- Some(constness),
+ constness,
)
}
@@ -666,7 +670,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
args,
infer_args,
Some(self_ty),
- Some(constness),
+ constness,
);
let tcx = self.tcx();
@@ -796,7 +800,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty: Ty<'tcx>,
trait_segment: &hir::PathSegment<'_>,
is_impl: bool,
- constness: Option<ty::BoundConstness>,
+ constness: ty::BoundConstness,
) -> ty::TraitRef<'tcx> {
let (substs, _) = self.create_substs_for_ast_trait_ref(
span,
@@ -820,7 +824,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty: Ty<'tcx>,
trait_segment: &'a hir::PathSegment<'a>,
is_impl: bool,
- constness: Option<ty::BoundConstness>,
+ constness: ty::BoundConstness,
) -> (SubstsRef<'tcx>, GenericArgCountResult) {
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
@@ -849,12 +853,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.is_some()
}
- // Sets `implicitly_sized` to true on `Bounds` if necessary
+ /// Sets `implicitly_sized` to true on `Bounds` if necessary
pub(crate) fn add_implicitly_sized<'hir>(
&self,
bounds: &mut Bounds<'hir>,
ast_bounds: &'hir [hir::GenericBound<'hir>],
- self_ty_where_predicates: Option<(hir::HirId, &'hir [hir::WherePredicate<'hir>])>,
+ self_ty_where_predicates: Option<(LocalDefId, &'hir [hir::WherePredicate<'hir>])>,
span: Span,
) {
let tcx = self.tcx();
@@ -874,19 +878,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
search_bounds(ast_bounds);
if let Some((self_ty, where_clause)) = self_ty_where_predicates {
- let self_ty_def_id = tcx.hir().local_def_id(self_ty).to_def_id();
for clause in where_clause {
if let hir::WherePredicate::BoundPredicate(pred) = clause {
- if pred.is_param_bound(self_ty_def_id) {
+ if pred.is_param_bound(self_ty.to_def_id()) {
search_bounds(pred.bounds);
}
}
}
}
- let sized_def_id = tcx.lang_items().require(LangItem::Sized);
+ let sized_def_id = tcx.lang_items().sized_trait();
match (&sized_def_id, unbound) {
- (Ok(sized_def_id), Some(tpb))
+ (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
@@ -906,7 +909,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// There was no `?Sized` bound; add implicitly sized if `Sized` is available.
}
}
- if sized_def_id.is_err() {
+ if sized_def_id.is_none() {
// No lang item for `Sized`, so we can't add it as a bound.
return;
}
@@ -961,9 +964,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
hir::GenericBound::Outlives(lifetime) => {
let region = self.ast_region_to_region(lifetime, None);
- bounds
- .region_bounds
- .push((ty::Binder::bind_with_vars(region, bound_vars), lifetime.span));
+ bounds.region_bounds.push((
+ ty::Binder::bind_with_vars(region, bound_vars),
+ lifetime.ident.span,
+ ));
}
}
}
@@ -1199,7 +1203,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
(_, _) => {
let got = if let Some(_) = term.ty() { "type" } else { "constant" };
let expected = def_kind.descr(assoc_item_def_id);
- tcx.sess
+ let reported = tcx
+ .sess
.struct_span_err(
binding.span,
&format!("expected {expected} bound, found {got}"),
@@ -1210,11 +1215,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
)
.emit();
term = match def_kind {
- hir::def::DefKind::AssocTy => tcx.ty_error().into(),
+ hir::def::DefKind::AssocTy => {
+ tcx.ty_error_with_guaranteed(reported).into()
+ }
hir::def::DefKind::AssocConst => tcx
- .const_error(
+ .const_error_with_guaranteed(
tcx.bound_type_of(assoc_item_def_id)
.subst(tcx, projection_ty.skip_binder().substs),
+ reported,
)
.into(),
_ => unreachable!(),
@@ -1332,8 +1340,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.map(|&(trait_ref, _, _)| trait_ref.def_id())
.find(|&trait_ref| tcx.is_trait_alias(trait_ref))
.map(|trait_ref| tcx.def_span(trait_ref));
- tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
- return tcx.ty_error();
+ let reported =
+ tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
+ return tcx.ty_error_with_guaranteed(reported);
}
// Check that there are no gross object safety violations;
@@ -1343,14 +1352,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let object_safety_violations =
astconv_object_safety_violations(tcx, item.trait_ref().def_id());
if !object_safety_violations.is_empty() {
- report_object_safety_error(
+ let reported = report_object_safety_error(
tcx,
span,
item.trait_ref().def_id(),
&object_safety_violations,
)
.emit();
- return tcx.ty_error();
+ return tcx.ty_error_with_guaranteed(reported);
}
}
@@ -1373,7 +1382,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(pred) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
let pred = bound_predicate.rebind(pred);
associated_types.entry(span).or_default().extend(
tcx.associated_items(pred.def_id())
@@ -1382,7 +1391,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.map(|item| item.def_id),
);
}
- ty::PredicateKind::Projection(pred) => {
+ ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
let pred = bound_predicate.rebind(pred);
// A `Self` within the original bound will be substituted with a
// `trait_object_dummy_self`, so check for that.
@@ -1812,7 +1821,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Check if we have an enum variant.
let mut variant_resolution = None;
- if let ty::Adt(adt_def, _) = qself_ty.kind() {
+ if let ty::Adt(adt_def, adt_substs) = qself_ty.kind() {
if adt_def.is_enum() {
let variant_def = adt_def
.variants()
@@ -1908,6 +1917,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
}
+
+ // see if we can satisfy using an inherent associated type
+ for &impl_ in tcx.inherent_impls(adt_def.did()) {
+ let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, impl_) else {
+ continue;
+ };
+ let item_substs = self.create_substs_for_associated_item(
+ span,
+ assoc_ty_did,
+ assoc_segment,
+ adt_substs,
+ );
+ let ty = tcx.bound_type_of(assoc_ty_did).subst(tcx, item_substs);
+ let ty = self.normalize_ty(span, ty);
+ return Ok((ty, DefKind::AssocTy, assoc_ty_did));
+ }
}
// Find the type of the associated item, and the trait where the associated
@@ -1977,7 +2002,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
err.emit()
- } else if let Some(reported) = qself_ty.error_reported() {
+ } else if let Err(reported) = qself_ty.error_reported() {
reported
} else {
// Don't print `TyErr` to the user.
@@ -1993,37 +2018,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
let trait_did = bound.def_id();
- let (assoc_ident, def_scope) =
- tcx.adjust_ident_and_get_scope(assoc_ident, trait_did, hir_ref_id);
-
- // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
- // of calling `filter_by_name_and_kind`.
- let item = tcx.associated_items(trait_did).in_definition_order().find(|i| {
- i.kind.namespace() == Namespace::TypeNS
- && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
- });
- // Assume that if it's not matched, there must be a const defined with the same name
- // but it was used in a type position.
- let Some(item) = item else {
+ let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, trait_did) else {
+ // Assume that if it's not matched, there must be a const defined with the same name
+ // but it was used in a type position.
let msg = format!("found associated const `{assoc_ident}` when type was expected");
let guar = tcx.sess.struct_span_err(span, &msg).emit();
return Err(guar);
};
- let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, assoc_segment, bound);
+ let ty = self.projected_ty_from_poly_trait_ref(span, assoc_ty_did, assoc_segment, bound);
let ty = self.normalize_ty(span, ty);
- let kind = DefKind::AssocTy;
- if !item.visibility(tcx).is_accessible_from(def_scope, tcx) {
- let kind = kind.descr(item.def_id);
- let msg = format!("{} `{}` is private", kind, assoc_ident);
- tcx.sess
- .struct_span_err(span, &msg)
- .span_label(span, &format!("private {}", kind))
- .emit();
- }
- tcx.check_stability(item.def_id, Some(hir_ref_id), span, None);
-
if let Some(variant_def_id) = variant_resolution {
tcx.struct_span_lint_hir(
AMBIGUOUS_ASSOCIATED_ITEMS,
@@ -2042,7 +2047,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
could_refer_to(DefKind::Variant, variant_def_id, "");
- could_refer_to(kind, item.def_id, " also");
+ could_refer_to(DefKind::AssocTy, assoc_ty_did, " also");
lint.span_suggestion(
span,
@@ -2055,7 +2060,40 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
},
);
}
- Ok((ty, kind, item.def_id))
+ Ok((ty, DefKind::AssocTy, assoc_ty_did))
+ }
+
+ fn lookup_assoc_ty(
+ &self,
+ ident: Ident,
+ block: hir::HirId,
+ span: Span,
+ scope: DefId,
+ ) -> Option<DefId> {
+ let tcx = self.tcx();
+ let (ident, def_scope) = tcx.adjust_ident_and_get_scope(ident, scope, block);
+
+ // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
+ // of calling `find_by_name_and_kind`.
+ let item = tcx.associated_items(scope).in_definition_order().find(|i| {
+ i.kind.namespace() == Namespace::TypeNS
+ && i.ident(tcx).normalize_to_macros_2_0() == ident
+ })?;
+
+ let kind = DefKind::AssocTy;
+ if !item.visibility(tcx).is_accessible_from(def_scope, tcx) {
+ let kind = kind.descr(item.def_id);
+ let msg = format!("{kind} `{ident}` is private");
+ let def_span = self.tcx().def_span(item.def_id);
+ tcx.sess
+ .struct_span_err_with_code(span, &msg, rustc_errors::error_code!(E0624))
+ .span_label(span, &format!("private {kind}"))
+ .span_label(def_span, &format!("{kind} defined here"))
+ .emit();
+ }
+ tcx.check_stability(item.def_id, Some(block), span, None);
+
+ Some(item.def_id)
}
fn qpath_to_ty(
@@ -2080,17 +2118,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
debug!("qpath_to_ty: self.item_def_id()={:?}", def_id);
- let parent_def_id = def_id
- .and_then(|def_id| {
- def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
- })
+ let parent_def_id = def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
.map(|hir_id| tcx.hir().get_parent_item(hir_id).to_def_id());
debug!("qpath_to_ty: parent_def_id={:?}", parent_def_id);
// If the trait in segment is the same as the trait defining the item,
// use the `<Self as ..>` syntax in the error.
- let is_part_of_self_trait_constraints = def_id == Some(trait_def_id);
+ let is_part_of_self_trait_constraints = def_id == trait_def_id;
let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id);
let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
@@ -2099,13 +2134,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
"Type"
};
- self.report_ambiguous_associated_type(
+ let reported = self.report_ambiguous_associated_type(
span,
type_name,
&path_str,
item_segment.ident.name,
);
- return tcx.ty_error();
+ return tcx.ty_error_with_guaranteed(reported)
};
debug!("qpath_to_ty: self_type={:?}", self_ty);
@@ -2116,7 +2151,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty,
trait_segment,
false,
- Some(constness),
+ constness,
);
let item_substs = self.create_substs_for_associated_item(
@@ -2365,7 +2400,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
path_segs
}
- // Check a type `Path` and convert it to a `Ty`.
+ /// Check a type `Path` and convert it to a `Ty`.
pub fn res_to_ty(
&self,
opt_self_ty: Option<Ty<'tcx>>,
@@ -2383,7 +2418,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
match path.res {
Res::Def(DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder, did) => {
// Check for desugared `impl Trait`.
- assert!(ty::is_impl_trait_defn(tcx, did).is_none());
+ assert!(tcx.is_type_alias_impl_trait(did));
let item_segment = path.segments.split_last().unwrap();
self.prohibit_generics(item_segment.1.iter(), |err| {
err.note("`impl Trait` types can't have type parameters");
@@ -2547,8 +2582,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
{
err.span_note(impl_.self_ty.span, "not a concrete type");
}
- err.emit();
- tcx.ty_error()
+ tcx.ty_error_with_guaranteed(err.emit())
} else {
self.normalize_ty(span, ty)
}
@@ -2596,8 +2630,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
Res::Err => {
- self.set_tainted_by_errors();
- self.tcx().ty_error()
+ let e = self
+ .tcx()
+ .sess
+ .delay_span_bug(path.span, "path with `Res:Err` but no error emitted");
+ self.set_tainted_by_errors(e);
+ self.tcx().ty_error_with_guaranteed(e)
}
_ => span_bug!(span, "unexpected resolution: {:?}", path.res),
}
@@ -2687,7 +2725,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&GenericArgs::none(),
true,
None,
- None,
+ ty::BoundConstness::NotConst,
);
EarlyBinder(self.normalize_ty(span, tcx.at(span).type_of(def_id)))
.subst(tcx, substs)
@@ -2696,8 +2734,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let length = match length {
&hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span),
hir::ArrayLen::Body(constant) => {
- let length_def_id = tcx.hir().local_def_id(constant.hir_id);
- ty::Const::from_anon_const(tcx, length_def_id)
+ ty::Const::from_anon_const(tcx, constant.def_id)
}
};
@@ -2705,7 +2742,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.normalize_ty(ast_ty.span, array_ty)
}
hir::TyKind::Typeof(ref e) => {
- let ty_erased = tcx.type_of(tcx.hir().local_def_id(e.hir_id));
+ let ty_erased = tcx.type_of(e.def_id);
let ty = tcx.fold_regions(ty_erased, |r, _| {
if r.is_erased() { tcx.lifetimes.re_static } else { r }
});
@@ -2750,35 +2787,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let substs = InternalSubsts::for_item(tcx, def_id, |param, _| {
if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) {
// Our own parameters are the resolved lifetimes.
- if let GenericParamDefKind::Lifetime = param.kind {
- if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] {
- self.ast_region_to_region(lifetime, None).into()
- } else {
- bug!()
- }
- } else {
- bug!()
- }
+ let GenericParamDefKind::Lifetime { .. } = param.kind else { bug!() };
+ let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { bug!() };
+ self.ast_region_to_region(lifetime, None).into()
} else {
- match param.kind {
- // For RPIT (return position impl trait), only lifetimes
- // mentioned in the impl Trait predicate are captured by
- // the opaque type, so the lifetime parameters from the
- // parent item need to be replaced with `'static`.
- //
- // For `impl Trait` in the types of statics, constants,
- // locals and type aliases. These capture all parent
- // lifetimes, so they can use their identity subst.
- GenericParamDefKind::Lifetime
- if matches!(
- origin,
- hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..)
- ) =>
- {
- tcx.lifetimes.re_static.into()
- }
- _ => tcx.mk_param_from_def(param),
- }
+ tcx.mk_param_from_def(param)
}
});
debug!("impl_trait_ty_to_ty: substs={:?}", substs);
@@ -2955,6 +2968,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Some(tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), ty))
}
+ #[instrument(level = "trace", skip(self, generate_err))]
fn validate_late_bound_regions(
&self,
constrained_regions: FxHashSet<ty::BoundRegionKind>,
@@ -2963,7 +2977,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) {
for br in referenced_regions.difference(&constrained_regions) {
let br_name = match *br {
- ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) | ty::BrEnv => {
+ ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) | ty::BrEnv => {
"an anonymous lifetime".to_string()
}
ty::BrNamed(_, name) => format!("lifetime `{}`", name),
@@ -2971,7 +2985,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut err = generate_err(&br_name);
- if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) = *br {
+ if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) = *br {
// The only way for an anonymous lifetime to wind up
// in the return type but **also** be unconstrained is
// if it only appears in "associated types" in the
@@ -2996,7 +3010,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
fn compute_object_lifetime_bound(
&self,
span: Span,
- existential_predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+ existential_predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
) -> Option<ty::Region<'tcx>> // if None, use the default
{
let tcx = self.tcx();
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index 6a28bb16a..3e3544ce6 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -60,13 +60,10 @@ impl<'tcx> Bounds<'tcx> {
{
// If it could be sized, and is, add the `Sized` predicate.
let sized_predicate = self.implicitly_sized.and_then(|span| {
- tcx.lang_items().sized_trait().map(move |sized| {
- let trait_ref = ty::Binder::dummy(ty::TraitRef {
- def_id: sized,
- substs: tcx.mk_substs_trait(param_ty, &[]),
- });
- (trait_ref.without_const().to_predicate(tcx), span)
- })
+ // FIXME: use tcx.at(span).mk_trait_ref(LangItem::Sized) here? This may make no-core code harder to write.
+ let sized = tcx.lang_items().sized_trait()?;
+ let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(sized, [param_ty]));
+ Some((trait_ref.without_const().to_predicate(tcx), span))
});
let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| {
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index b70ac0205..fc0ca6209 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1,4 +1,5 @@
use crate::check::intrinsicck::InlineAsmCtxt;
+use crate::errors::LinkageType;
use super::compare_method::check_type_bounds;
use super::compare_method::{compare_impl_method, compare_ty_impl};
@@ -6,10 +7,11 @@ use super::*;
use rustc_attr as attr;
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{ItemKind, Node, PathSegment};
+use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
@@ -19,13 +21,12 @@ use rustc_middle::middle::stability::EvalResult;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{
- self, ParamEnv, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
-};
+use rustc_middle::ty::{self, AdtDef, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
use rustc_span::symbol::sym;
use rustc_span::{self, Span};
use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCtxt};
@@ -75,7 +76,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
check_simd(tcx, span, def_id);
}
- check_transparent(tcx, span, def);
+ check_transparent(tcx, def);
check_packed(tcx, span, def);
}
@@ -83,7 +84,7 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id);
def.destructor(tcx); // force the destructor to be evaluated
- check_transparent(tcx, span, def);
+ check_transparent(tcx, def);
check_union_fields(tcx, span, def_id);
check_packed(tcx, span, def);
}
@@ -230,7 +231,9 @@ fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
let substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id());
let span = tcx.def_span(item.owner_id.def_id);
- check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span);
+ if !tcx.features().impl_trait_projections {
+ check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span);
+ }
if tcx.type_of(item.owner_id.def_id).references_error() {
return;
}
@@ -239,6 +242,7 @@ fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
}
check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin);
}
+
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
/// in "inheriting lifetimes".
#[instrument(level = "debug", skip(tcx, span))]
@@ -250,39 +254,11 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
let item = tcx.hir().expect_item(def_id);
debug!(?item, ?span);
- struct FoundParentLifetime;
- struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics);
- impl<'tcx> ty::visit::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> {
- type BreakTy = FoundParentLifetime;
-
- fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
- debug!("FindParentLifetimeVisitor: r={:?}", r);
- if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *r {
- if index < self.0.parent_count as u32 {
- return ControlFlow::Break(FoundParentLifetime);
- } else {
- return ControlFlow::CONTINUE;
- }
- }
-
- r.super_visit_with(self)
- }
-
- fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- if let ty::ConstKind::Unevaluated(..) = c.kind() {
- // FIXME(#72219) We currently don't detect lifetimes within substs
- // which would violate this check. Even though the particular substitution is not used
- // within the const, this should still be fixed.
- return ControlFlow::CONTINUE;
- }
- c.super_visit_with(self)
- }
- }
-
struct ProhibitOpaqueVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
opaque_identity_ty: Ty<'tcx>,
- generics: &'tcx ty::Generics,
+ parent_count: u32,
+ references_parent_regions: bool,
selftys: Vec<(Span, Option<String>)>,
}
@@ -290,12 +266,25 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
type BreakTy = Ty<'tcx>;
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
+ debug!(?t, "root_visit_ty");
if t == self.opaque_identity_ty {
ControlFlow::CONTINUE
} else {
- t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics))
- .map_break(|FoundParentLifetime| t)
+ t.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
+ tcx: self.tcx,
+ op: |region| {
+ if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *region
+ && index < self.parent_count
+ {
+ self.references_parent_regions= true;
+ }
+ },
+ });
+ if self.references_parent_regions {
+ ControlFlow::Break(t)
+ } else {
+ ControlFlow::CONTINUE
+ }
}
}
}
@@ -328,15 +317,20 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
if let ItemKind::OpaqueTy(hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
+ in_trait,
..
}) = item.kind
{
+ let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+ let opaque_identity_ty = if in_trait {
+ tcx.mk_projection(def_id.to_def_id(), substs)
+ } else {
+ tcx.mk_opaque(def_id.to_def_id(), substs)
+ };
let mut visitor = ProhibitOpaqueVisitor {
- opaque_identity_ty: tcx.mk_opaque(
- def_id.to_def_id(),
- InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
- ),
- generics: tcx.generics_of(def_id),
+ opaque_identity_ty,
+ parent_count: tcx.generics_of(def_id).parent_count as u32,
+ references_parent_regions: false,
tcx,
selftys: vec![],
};
@@ -344,10 +338,6 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
.explicit_item_bounds(def_id)
.iter()
.try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
- debug!(
- "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor.opaque_identity_ty={:?}, visitor.generics={:?}",
- prohibit_opaque, visitor.opaque_identity_ty, visitor.generics
- );
if let Some(ty) = prohibit_opaque.break_value() {
visitor.visit_item(&item);
@@ -358,15 +348,16 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
_ => unreachable!(),
};
- let mut err = struct_span_err!(
- tcx.sess,
+ let mut err = feature_err(
+ &tcx.sess.parse_sess,
+ sym::impl_trait_projections,
span,
- E0760,
- "`{}` return type cannot contain a projection or `Self` that references lifetimes from \
- a parent scope",
- if is_async { "async fn" } else { "impl Trait" },
+ &format!(
+ "`{}` return type cannot contain a projection or `Self` that references \
+ lifetimes from a parent scope",
+ if is_async { "async fn" } else { "impl Trait" },
+ ),
);
-
for (span, name) in visitor.selftys {
err.span_suggestion(
span,
@@ -450,8 +441,8 @@ fn check_opaque_meets_bounds<'tcx>(
let misc_cause = traits::ObligationCause::misc(span, hir_id);
- match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_ty) {
- Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
+ match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {
+ Ok(()) => {}
Err(ty_err) => {
tcx.sess.delay_span_bug(
span,
@@ -463,15 +454,14 @@ fn check_opaque_meets_bounds<'tcx>(
// Additionally require the hidden type to be well-formed with only the generics of the opaque type.
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
// hidden type is well formed even without those bounds.
- let predicate =
- ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_ty.into())).to_predicate(tcx);
- ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
+ let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_ty.into()));
+ ocx.register_obligation(Obligation::new(tcx, misc_cause, param_env, predicate));
// Check that all obligations are satisfied by the implementation's
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None);
}
match origin {
// Checked when type checking the function containing them.
@@ -489,6 +479,36 @@ fn check_opaque_meets_bounds<'tcx>(
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
}
+fn is_enum_of_nonnullable_ptr<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ adt_def: AdtDef<'tcx>,
+ substs: SubstsRef<'tcx>,
+) -> bool {
+ if adt_def.repr().inhibit_enum_layout_opt() {
+ return false;
+ }
+
+ let [var_one, var_two] = &adt_def.variants().raw[..] else {
+ return false;
+ };
+ let (([], [field]) | ([field], [])) = (&var_one.fields[..], &var_two.fields[..]) else {
+ return false;
+ };
+ matches!(field.ty(tcx, substs).kind(), ty::FnPtr(..) | ty::Ref(..))
+}
+
+fn check_static_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
+ if tcx.codegen_fn_attrs(def_id).import_linkage.is_some() {
+ if match tcx.type_of(def_id).kind() {
+ ty::RawPtr(_) => false,
+ ty::Adt(adt_def, substs) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *substs),
+ _ => true,
+ } {
+ tcx.sess.emit_err(LinkageType { span: tcx.def_span(def_id) });
+ }
+ }
+}
+
fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
debug!(
"check_item_type(it.def_id={:?}, it.name={})",
@@ -501,16 +521,13 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
tcx.ensure().typeck(id.owner_id.def_id);
maybe_check_static_with_link_section(tcx, id.owner_id.def_id);
check_static_inhabited(tcx, id.owner_id.def_id);
+ check_static_linkage(tcx, id.owner_id.def_id);
}
DefKind::Const => {
tcx.ensure().typeck(id.owner_id.def_id);
}
DefKind::Enum => {
- let item = tcx.hir().item(id);
- let hir::ItemKind::Enum(ref enum_definition, _) = item.kind else {
- return;
- };
- check_enum(tcx, &enum_definition.variants, item.owner_id.def_id);
+ check_enum(tcx, id.owner_id.def_id);
}
DefKind::Fn => {} // entirely within check_item_body
DefKind::Impl => {
@@ -642,6 +659,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
}
hir::ForeignItemKind::Static(..) => {
check_static_inhabited(tcx, def_id);
+ check_static_linkage(tcx, def_id);
}
_ => {}
}
@@ -659,7 +677,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
// an error would be reported if this fails.
- let _ = traits::OnUnimplementedDirective::of_item(tcx, item.owner_id.to_def_id());
+ let _ = OnUnimplementedDirective::of_item(tcx, item.owner_id.to_def_id());
}
pub(super) fn check_specialization_validity<'tcx>(
@@ -1026,7 +1044,7 @@ pub(super) fn check_packed_inner(
None
}
-pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtDef<'tcx>) {
+pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {
if !adt.repr().transparent() {
return;
}
@@ -1035,14 +1053,14 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
feature_err(
&tcx.sess.parse_sess,
sym::transparent_unions,
- sp,
+ tcx.def_span(adt.did()),
"transparent unions are unstable",
)
.emit();
}
if adt.variants().len() != 1 {
- bad_variant_count(tcx, adt, sp, adt.did());
+ bad_variant_count(tcx, adt, tcx.def_span(adt.did()), adt.did());
if adt.variants().is_empty() {
// Don't bother checking the fields. No variants (and thus no fields) exist.
return;
@@ -1103,7 +1121,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
.filter_map(|(span, zst, _align1, _non_exhaustive)| if !zst { Some(span) } else { None });
let non_zst_count = non_zst_fields.clone().count();
if non_zst_count >= 2 {
- bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
+ bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did()));
}
let incompatible_zst_fields =
field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
@@ -1143,12 +1161,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
}
#[allow(trivial_numeric_casts)]
-fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: LocalDefId) {
+fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
let def = tcx.adt_def(def_id);
- let sp = tcx.def_span(def_id);
def.destructor(tcx); // force the destructor to be evaluated
- if vs.is_empty() {
+ if def.variants().is_empty() {
if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() {
struct_span_err!(
tcx.sess,
@@ -1156,7 +1173,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
E0084,
"unsupported representation for zero-variant enum"
)
- .span_label(sp, "zero-variant enum")
+ .span_label(tcx.def_span(def_id), "zero-variant enum")
.emit();
}
}
@@ -1167,88 +1184,96 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
feature_err(
&tcx.sess.parse_sess,
sym::repr128,
- sp,
+ tcx.def_span(def_id),
"repr with 128-bit type is unstable",
)
.emit();
}
}
- for v in vs {
- if let Some(ref e) = v.disr_expr {
- tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id));
+ for v in def.variants() {
+ if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr {
+ tcx.ensure().typeck(discr_def_id.expect_local());
}
}
- if tcx.adt_def(def_id).repr().int.is_none() {
- let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..));
+ if def.repr().int.is_none() {
+ let is_unit = |var: &ty::VariantDef| matches!(var.ctor_kind(), Some(CtorKind::Const));
+ let has_disr = |var: &ty::VariantDef| matches!(var.discr, ty::VariantDiscr::Explicit(_));
- let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
- let has_non_units = vs.iter().any(|var| !is_unit(var));
- let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var));
- let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var));
+ let has_non_units = def.variants().iter().any(|var| !is_unit(var));
+ let disr_units = def.variants().iter().any(|var| is_unit(&var) && has_disr(&var));
+ let disr_non_unit = def.variants().iter().any(|var| !is_unit(&var) && has_disr(&var));
if disr_non_unit || (disr_units && has_non_units) {
- let mut err =
- struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified");
+ let mut err = struct_span_err!(
+ tcx.sess,
+ tcx.def_span(def_id),
+ E0732,
+ "`#[repr(inttype)]` must be specified"
+ );
err.emit();
}
}
- detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
-
- check_transparent(tcx, sp, def);
+ detect_discriminant_duplicate(tcx, def);
+ check_transparent(tcx, def);
}
/// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal
-fn detect_discriminant_duplicate<'tcx>(
- tcx: TyCtxt<'tcx>,
- mut discrs: Vec<(VariantIdx, Discr<'tcx>)>,
- vs: &'tcx [hir::Variant<'tcx>],
- self_span: Span,
-) {
+fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {
// Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate.
// Here `idx` refers to the order of which the discriminant appears, and its index in `vs`
- let report = |dis: Discr<'tcx>, idx: usize, err: &mut Diagnostic| {
- let var = &vs[idx]; // HIR for the duplicate discriminant
- let (span, display_discr) = match var.disr_expr {
- Some(ref expr) => {
+ let report = |dis: Discr<'tcx>, idx, err: &mut Diagnostic| {
+ let var = adt.variant(idx); // HIR for the duplicate discriminant
+ 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::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
+ 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
{
- (tcx.hir().span(expr.hir_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
- // Otherwise, format the value as-is
+ (tcx.def_span(discr_def_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
} else {
- (tcx.hir().span(expr.hir_id), format!("`{dis}`"))
+ // Otherwise, format the value as-is
+ (tcx.def_span(discr_def_id), format!("`{dis}`"))
}
}
- None => {
+ // This should not happen.
+ ty::VariantDiscr::Relative(0) => (tcx.def_span(var.def_id), format!("`{dis}`")),
+ ty::VariantDiscr::Relative(distance_to_explicit) => {
// At this point we know this discriminant is a duplicate, and was not explicitly
// assigned by the user. Here we iterate backwards to fetch the HIR for the last
// explicitly assigned discriminant, and letting the user know that this was the
// increment startpoint, and how many steps from there leading to the duplicate
- if let Some((n, hir::Variant { span, ident, .. })) =
- vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some())
+ if let Some(explicit_idx) =
+ idx.as_u32().checked_sub(distance_to_explicit).map(VariantIdx::from_u32)
{
- let ve_ident = var.ident;
- let n = n + 1;
- let sp = if n > 1 { "variants" } else { "variant" };
+ let explicit_variant = adt.variant(explicit_idx);
+ let ve_ident = var.name;
+ let ex_ident = explicit_variant.name;
+ let sp = if distance_to_explicit > 1 { "variants" } else { "variant" };
err.span_label(
- *span,
- format!("discriminant for `{ve_ident}` incremented from this startpoint (`{ident}` + {n} {sp} later => `{ve_ident}` = {dis})"),
+ tcx.def_span(explicit_variant.def_id),
+ format!(
+ "discriminant for `{ve_ident}` incremented from this startpoint \
+ (`{ex_ident}` + {distance_to_explicit} {sp} later \
+ => `{ve_ident}` = {dis})"
+ ),
);
}
- (vs[idx].span, format!("`{dis}`"))
+ (tcx.def_span(var.def_id), format!("`{dis}`"))
}
};
err.span_label(span, format!("{display_discr} assigned here"));
};
+ let mut discrs = adt.discriminants(tcx).collect::<Vec<_>>();
+
// Here we loop through the discriminants, comparing each discriminant to another.
// When a duplicate is detected, we instantiate an error and point to both
// initial and duplicate value. The duplicate discriminant is then discarded by swapping
@@ -1257,29 +1282,29 @@ fn detect_discriminant_duplicate<'tcx>(
// style as we are mutating `discrs` on the fly).
let mut i = 0;
while i < discrs.len() {
- let hir_var_i_idx = discrs[i].0.index();
+ let var_i_idx = discrs[i].0;
let mut error: Option<DiagnosticBuilder<'_, _>> = None;
let mut o = i + 1;
while o < discrs.len() {
- let hir_var_o_idx = discrs[o].0.index();
+ let var_o_idx = discrs[o].0;
if discrs[i].1.val == discrs[o].1.val {
let err = error.get_or_insert_with(|| {
let mut ret = struct_span_err!(
tcx.sess,
- self_span,
+ tcx.def_span(adt.did()),
E0081,
"discriminant value `{}` assigned more than once",
discrs[i].1,
);
- report(discrs[i].1, hir_var_i_idx, &mut ret);
+ report(discrs[i].1, var_i_idx, &mut ret);
ret
});
- report(discrs[o].1, hir_var_o_idx, err);
+ report(discrs[o].1, var_o_idx, err);
// Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty
discrs[o] = *discrs.last().unwrap();
diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs
index 32f66b06f..db150ebf0 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_method.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs
@@ -1,7 +1,7 @@
use super::potentially_plural_count;
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
use hir::def_id::{DefId, LocalDefId};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
@@ -9,13 +9,12 @@ use rustc_hir::intravisit;
use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{self, TyCtxtInferExt};
+use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::util;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::util::ExplicitSelf;
-use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::{
- self, AssocItem, DefIdTree, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
+ self, DefIdTree, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
};
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
use rustc_span::Span;
@@ -50,11 +49,11 @@ pub(crate) fn compare_impl_method<'tcx>(
return;
}
- if let Err(_) = compare_number_of_generics(tcx, impl_m, impl_m_span, trait_m, trait_item_span) {
+ if let Err(_) = compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span, false) {
return;
}
- if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m) {
+ if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m, false) {
return;
}
@@ -68,8 +67,14 @@ pub(crate) fn compare_impl_method<'tcx>(
return;
}
- if let Err(_) = compare_predicate_entailment(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
- {
+ if let Err(_) = compare_predicate_entailment(
+ tcx,
+ impl_m,
+ impl_m_span,
+ trait_m,
+ impl_trait_ref,
+ CheckImpliedWfMode::Check,
+ ) {
return;
}
}
@@ -143,10 +148,11 @@ pub(crate) fn compare_impl_method<'tcx>(
#[instrument(level = "debug", skip(tcx, impl_m_span, impl_trait_ref))]
fn compare_predicate_entailment<'tcx>(
tcx: TyCtxt<'tcx>,
- impl_m: &AssocItem,
+ impl_m: &ty::AssocItem,
impl_m_span: Span,
- trait_m: &AssocItem,
+ trait_m: &ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>,
+ check_implied_wf: CheckImpliedWfMode,
) -> Result<(), ErrorGuaranteed> {
let trait_to_impl_substs = impl_trait_ref.substs;
@@ -156,8 +162,7 @@ fn compare_predicate_entailment<'tcx>(
// FIXME(@lcnr): remove that after removing `cause.body_id` from
// obligations.
let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- // We sometimes modify the span further down.
- let mut cause = ObligationCause::new(
+ let cause = ObligationCause::new(
impl_m_span,
impl_m_hir_id,
ObligationCauseCode::CompareImplItemObligation {
@@ -175,13 +180,11 @@ fn compare_predicate_entailment<'tcx>(
impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs);
- let impl_m_generics = tcx.generics_of(impl_m.def_id);
- let trait_m_generics = tcx.generics_of(trait_m.def_id);
let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
let trait_m_predicates = tcx.predicates_of(trait_m.def_id);
// Check region bounds.
- check_region_bounds_on_impl_item(tcx, impl_m, trait_m, &trait_m_generics, &impl_m_generics)?;
+ check_region_bounds_on_impl_item(tcx, impl_m, trait_m, false)?;
// Create obligations for each predicate declared by the impl
// definition in the context of the trait's parameter
@@ -220,14 +223,11 @@ fn compare_predicate_entailment<'tcx>(
debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
- let mut selcx = traits::SelectionContext::new(&infcx);
let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
- let traits::Normalized { value: predicate, obligations } =
- traits::normalize(&mut selcx, param_env, normalize_cause, predicate);
+ let predicate = ocx.normalize(&normalize_cause, param_env, predicate);
- ocx.register_obligations(obligations);
let cause = ObligationCause::new(
span,
impl_m_hir_id,
@@ -237,7 +237,7 @@ fn compare_predicate_entailment<'tcx>(
kind: impl_m.kind,
},
);
- ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
+ ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
}
// We now need to check that the signature of the impl method is
@@ -256,17 +256,17 @@ fn compare_predicate_entailment<'tcx>(
// Compute placeholder form of impl and trait method tys.
let tcx = infcx.tcx;
- let mut wf_tys = FxHashSet::default();
+ let mut wf_tys = FxIndexSet::default();
- let impl_sig = infcx.replace_bound_vars_with_fresh_vars(
+ let unnormalized_impl_sig = infcx.replace_bound_vars_with_fresh_vars(
impl_m_span,
infer::HigherRankedType,
tcx.fn_sig(impl_m.def_id),
);
+ let unnormalized_impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(unnormalized_impl_sig));
let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id);
- let impl_sig = ocx.normalize(norm_cause.clone(), param_env, impl_sig);
- let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
+ let impl_fty = ocx.normalize(&norm_cause, param_env, unnormalized_impl_fty);
debug!("compare_impl_method: impl_fty={:?}", impl_fty);
let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
@@ -276,7 +276,7 @@ fn compare_predicate_entailment<'tcx>(
// we have to do this before normalization, since the normalized ty may
// not contain the input parameters. See issue #87748.
wf_tys.extend(trait_sig.inputs_and_output.iter());
- let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig);
+ let trait_sig = ocx.normalize(&norm_cause, param_env, trait_sig);
// We also have to add the normalized trait signature
// as we don't normalize during implied bounds computation.
wf_tys.extend(trait_sig.inputs_and_output.iter());
@@ -290,147 +290,126 @@ fn compare_predicate_entailment<'tcx>(
// type would be more appropriate. In other places we have a `Vec<Span>`
// corresponding to their `Vec<Predicate>`, but we don't have that here.
// Fixing this would improve the output of test `issue-83765.rs`.
- let mut result = infcx
- .at(&cause, param_env)
- .sup(trait_fty, impl_fty)
- .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok));
-
- // HACK(RPITIT): #101614. When we are trying to infer the hidden types for
- // RPITITs, we need to equate the output tys instead of just subtyping. If
- // we just use `sup` above, we'll end up `&'static str <: _#1t`, which causes
- // us to infer `_#1t = #'_#2r str`, where `'_#2r` is unconstrained, which gets
- // fixed up to `ReEmpty`, and which is certainly not what we want.
- if trait_fty.has_infer_types() {
- result = result.and_then(|()| {
- infcx
- .at(&cause, param_env)
- .eq(trait_sig.output(), impl_sig.output())
- .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok))
- });
- }
+ let result = ocx.sup(&cause, param_env, trait_fty, impl_fty);
if let Err(terr) = result {
- debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
-
- let (impl_err_span, trait_err_span) =
- extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
-
- cause.span = impl_err_span;
-
- let mut diag = struct_span_err!(
- tcx.sess,
- cause.span(),
- E0053,
- "method `{}` has an incompatible type for trait",
- trait_m.name
- );
- match &terr {
- TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
- if trait_m.fn_has_self_parameter =>
- {
- let ty = trait_sig.inputs()[0];
- let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) {
- ExplicitSelf::ByValue => "self".to_owned(),
- ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
- ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
- _ => format!("self: {ty}"),
- };
-
- // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
- // span points only at the type `Box<Self`>, but we want to cover the whole
- // argument pattern and type.
- let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
- ImplItemKind::Fn(ref sig, body) => tcx
- .hir()
- .body_param_names(body)
- .zip(sig.decl.inputs.iter())
- .map(|(param, ty)| param.span.to(ty.span))
- .next()
- .unwrap_or(impl_err_span),
- _ => bug!("{:?} is not a method", impl_m),
- };
-
- diag.span_suggestion(
- span,
- "change the self-receiver type to match the trait",
- sugg,
- Applicability::MachineApplicable,
- );
- }
- TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
- 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.
- match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
- ImplItemKind::Fn(ref sig, _)
- if sig.header.asyncness == hir::IsAsync::NotAsync =>
- {
- 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());
- diag.span_suggestion_verbose(sp, msg, sugg, ap);
- }
- hir::FnRetTy::Return(hir_ty) => {
- let sugg = trait_sig.output();
- diag.span_suggestion(hir_ty.span, msg, sugg, ap);
- }
- };
- }
- _ => {}
- };
- } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
- diag.span_suggestion(
- impl_err_span,
- "change the parameter type to match the trait",
- trait_ty,
- Applicability::MachineApplicable,
- );
- }
- }
- _ => {}
- }
+ debug!(?terr, "sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
- infcx.err_ctxt().note_type_err(
- &mut diag,
- &cause,
- trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
- Some(infer::ValuePairs::Terms(ExpectedFound {
- expected: trait_fty.into(),
- found: impl_fty.into(),
- })),
+ let emitted = report_trait_method_mismatch(
+ &infcx,
+ cause,
terr,
- false,
- false,
+ (trait_m, trait_fty),
+ (impl_m, impl_fty),
+ trait_sig,
+ impl_trait_ref,
);
+ return Err(emitted);
+ }
- return Err(diag.emit());
+ if check_implied_wf == CheckImpliedWfMode::Check {
+ // We need to check that the impl's args are well-formed given
+ // the hybrid param-env (impl + trait method where-clauses).
+ ocx.register_obligation(traits::Obligation::new(
+ infcx.tcx,
+ ObligationCause::dummy(),
+ param_env,
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
+ ));
}
+ let emit_implied_wf_lint = || {
+ infcx.tcx.struct_span_lint_hir(
+ rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
+ impl_m_hir_id,
+ infcx.tcx.def_span(impl_m.def_id),
+ "impl method assumes more implied bounds than the corresponding trait method",
+ |lint| lint,
+ );
+ };
// Check that all obligations are satisfied by the implementation's
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
- return Err(reported);
+ match check_implied_wf {
+ CheckImpliedWfMode::Check => {
+ return compare_predicate_entailment(
+ tcx,
+ impl_m,
+ impl_m_span,
+ trait_m,
+ impl_trait_ref,
+ CheckImpliedWfMode::Skip,
+ )
+ .map(|()| {
+ // If the skip-mode was successful, emit a lint.
+ emit_implied_wf_lint();
+ });
+ }
+ CheckImpliedWfMode::Skip => {
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
+ return Err(reported);
+ }
+ }
}
// Finally, resolve all regions. This catches wily misuses of
// lifetime parameters.
- let outlives_environment = OutlivesEnvironment::with_bounds(
+ let outlives_env = OutlivesEnvironment::with_bounds(
param_env,
Some(infcx),
- infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
+ infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys.clone()),
);
- infcx.check_region_obligations_and_report_errors(
- impl_m.def_id.expect_local(),
- &outlives_environment,
+ infcx.process_registered_region_obligations(
+ outlives_env.region_bound_pairs(),
+ outlives_env.param_env,
);
+ let errors = infcx.resolve_regions(&outlives_env);
+ if !errors.is_empty() {
+ // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT
+ // becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors`
+ match check_implied_wf {
+ CheckImpliedWfMode::Check => {
+ return compare_predicate_entailment(
+ tcx,
+ impl_m,
+ impl_m_span,
+ trait_m,
+ impl_trait_ref,
+ CheckImpliedWfMode::Skip,
+ )
+ .map(|()| {
+ // If the skip-mode was successful, emit a lint.
+ emit_implied_wf_lint();
+ });
+ }
+ CheckImpliedWfMode::Skip => {
+ if infcx.tainted_by_errors().is_none() {
+ infcx.err_ctxt().report_region_errors(impl_m.def_id.expect_local(), &errors);
+ }
+ return Err(tcx
+ .sess
+ .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted"));
+ }
+ }
+ }
Ok(())
}
+#[derive(Debug, PartialEq, Eq)]
+enum CheckImpliedWfMode {
+ /// Checks implied well-formedness of the impl method. If it fails, we will
+ /// re-check with `Skip`, and emit a lint if it succeeds.
+ Check,
+ /// Skips checking implied well-formedness of the impl method, but will emit
+ /// a lint if the `compare_predicate_entailment` succeeded. This means that
+ /// the reason that we had failed earlier during `Check` was due to the impl
+ /// having stronger requirements than the trait.
+ Skip,
+}
+
+#[instrument(skip(tcx), level = "debug", ret)]
pub fn collect_trait_impl_trait_tys<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
@@ -440,6 +419,11 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
let param_env = tcx.param_env(def_id);
+ // First, check a few of the same thing as `compare_impl_method`, just so we don't ICE during substitutions later.
+ compare_number_of_generics(tcx, impl_m, trait_m, tcx.hir().span_if_local(impl_m.def_id), true)?;
+ compare_generic_param_kinds(tcx, impl_m, trait_m, true)?;
+ check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?;
+
let trait_to_impl_substs = impl_trait_ref.substs;
let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
@@ -464,9 +448,10 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
let infcx = &tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(infcx);
+ // Normalize the impl signature with fresh variables for lifetime inference.
let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id);
let impl_sig = ocx.normalize(
- norm_cause.clone(),
+ &norm_cause,
param_env,
infcx.replace_bound_vars_with_fresh_vars(
return_span,
@@ -476,6 +461,10 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
);
let impl_return_ty = impl_sig.output();
+ // Normalize the trait signature with liberated bound vars, passing it through
+ // the ImplTraitInTraitCollector, which gathers all of the RPITITs and replaces
+ // them with inference variables.
+ // We will use these inference variables to collect the hidden types of RPITITs.
let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
let unnormalized_trait_sig = tcx
.liberate_late_bound_regions(
@@ -483,17 +472,15 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
)
.fold_with(&mut collector);
- let trait_sig = ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_sig);
+ let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig);
let trait_return_ty = trait_sig.output();
- let wf_tys = FxHashSet::from_iter(
+ let wf_tys = FxIndexSet::from_iter(
unnormalized_trait_sig.inputs_and_output.iter().chain(trait_sig.inputs_and_output.iter()),
);
- match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) {
- Ok(infer::InferOk { value: (), obligations }) => {
- ocx.register_obligations(obligations);
- }
+ match ocx.eq(&cause, param_env, trait_return_ty, impl_return_ty) {
+ Ok(()) => {}
Err(terr) => {
let mut diag = struct_span_err!(
tcx.sess,
@@ -521,23 +508,32 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
}
}
+ debug!(?trait_sig, ?impl_sig, "equating function signatures");
+
+ let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
+ let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
+
// Unify the whole function signature. We need to do this to fully infer
// the lifetimes of the return type, but do this after unifying just the
// return types, since we want to avoid duplicating errors from
// `compare_predicate_entailment`.
- match infcx
- .at(&cause, param_env)
- .eq(tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)), tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig)))
- {
- Ok(infer::InferOk { value: (), obligations }) => {
- ocx.register_obligations(obligations);
- }
+ match ocx.eq(&cause, param_env, trait_fty, impl_fty) {
+ Ok(()) => {}
Err(terr) => {
- let guar = tcx.sess.delay_span_bug(
- return_span,
- format!("could not unify `{trait_sig}` and `{impl_sig}`: {terr:?}"),
+ // This function gets called during `compare_predicate_entailment` when normalizing a
+ // signature that contains RPITIT. When the method signatures don't match, we have to
+ // emit an error now because `compare_predicate_entailment` will not report the error
+ // when normalization fails.
+ let emitted = report_trait_method_mismatch(
+ infcx,
+ cause,
+ terr,
+ (trait_m, trait_fty),
+ (impl_m, impl_fty),
+ trait_sig,
+ impl_trait_ref,
);
- return Err(guar);
+ return Err(emitted);
}
}
@@ -545,7 +541,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
// RPITs.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return Err(reported);
}
@@ -597,7 +593,13 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
let num_trait_substs = trait_to_impl_substs.len();
let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len();
let ty = tcx.fold_regions(ty, |region, _| {
- let (ty::ReFree(_) | ty::ReEarlyBound(_)) = region.kind() else { return region; };
+ match region.kind() {
+ // Remap all free regions, which correspond to late-bound regions in the function.
+ ty::ReFree(_) => {}
+ // Remap early-bound regions as long as they don't come from the `impl` itself.
+ ty::ReEarlyBound(ebr) if tcx.parent(ebr.def_id) != impl_m.container_id(tcx) => {}
+ _ => return region,
+ }
let Some(ty::ReEarlyBound(e)) = map.get(&region.into()).map(|r| r.expect_region().kind())
else {
tcx
@@ -618,11 +620,11 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
collected_tys.insert(def_id, ty);
}
Err(err) => {
- tcx.sess.delay_span_bug(
+ let reported = tcx.sess.delay_span_bug(
return_span,
format!("could not fully resolve: {ty} => {err:?}"),
);
- collected_tys.insert(def_id, tcx.ty_error());
+ collected_tys.insert(def_id, tcx.ty_error_with_guaranteed(reported));
}
}
}
@@ -675,12 +677,13 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
for (pred, pred_span) in self.tcx().bound_explicit_item_bounds(proj.item_def_id).subst_iter_copied(self.tcx(), proj.substs) {
let pred = pred.fold_with(self);
let pred = self.ocx.normalize(
- ObligationCause::misc(self.span, self.body_id),
+ &ObligationCause::misc(self.span, self.body_id),
self.param_env,
pred,
);
self.ocx.register_obligation(traits::Obligation::new(
+ self.tcx(),
ObligationCause::new(
self.span,
self.body_id,
@@ -697,16 +700,121 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
}
}
+fn report_trait_method_mismatch<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ mut cause: ObligationCause<'tcx>,
+ terr: TypeError<'tcx>,
+ (trait_m, trait_fty): (&ty::AssocItem, Ty<'tcx>),
+ (impl_m, impl_fty): (&ty::AssocItem, Ty<'tcx>),
+ trait_sig: ty::FnSig<'tcx>,
+ impl_trait_ref: ty::TraitRef<'tcx>,
+) -> ErrorGuaranteed {
+ let tcx = infcx.tcx;
+ let (impl_err_span, trait_err_span) =
+ extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
+
+ let mut diag = struct_span_err!(
+ tcx.sess,
+ impl_err_span,
+ E0053,
+ "method `{}` has an incompatible type for trait",
+ trait_m.name
+ );
+ match &terr {
+ TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
+ if trait_m.fn_has_self_parameter =>
+ {
+ let ty = trait_sig.inputs()[0];
+ let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) {
+ ExplicitSelf::ByValue => "self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
+ _ => format!("self: {ty}"),
+ };
+
+ // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
+ // span points only at the type `Box<Self`>, but we want to cover the whole
+ // argument pattern and type.
+ let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+ ImplItemKind::Fn(ref sig, body) => tcx
+ .hir()
+ .body_param_names(body)
+ .zip(sig.decl.inputs.iter())
+ .map(|(param, ty)| param.span.to(ty.span))
+ .next()
+ .unwrap_or(impl_err_span),
+ _ => bug!("{:?} is not a method", impl_m),
+ };
+
+ diag.span_suggestion(
+ span,
+ "change the self-receiver type to match the trait",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+ TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
+ 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.
+ match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+ ImplItemKind::Fn(ref sig, _) if !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());
+ diag.span_suggestion_verbose(sp, msg, sugg, ap);
+ }
+ hir::FnRetTy::Return(hir_ty) => {
+ let sugg = trait_sig.output();
+ diag.span_suggestion(hir_ty.span, msg, sugg, ap);
+ }
+ };
+ }
+ _ => {}
+ };
+ } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
+ diag.span_suggestion(
+ impl_err_span,
+ "change the parameter type to match the trait",
+ trait_ty,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ _ => {}
+ }
+
+ cause.span = impl_err_span;
+ infcx.err_ctxt().note_type_err(
+ &mut diag,
+ &cause,
+ trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
+ Some(infer::ValuePairs::Terms(ExpectedFound {
+ expected: trait_fty.into(),
+ found: impl_fty.into(),
+ })),
+ terr,
+ false,
+ false,
+ );
+
+ return diag.emit();
+}
+
fn check_region_bounds_on_impl_item<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m: &ty::AssocItem,
trait_m: &ty::AssocItem,
- trait_generics: &ty::Generics,
- impl_generics: &ty::Generics,
+ delay: bool,
) -> Result<(), ErrorGuaranteed> {
- let trait_params = trait_generics.own_counts().lifetimes;
+ let impl_generics = tcx.generics_of(impl_m.def_id);
let impl_params = impl_generics.own_counts().lifetimes;
+ let trait_generics = tcx.generics_of(trait_m.def_id);
+ let trait_params = trait_generics.own_counts().lifetimes;
+
debug!(
"check_region_bounds_on_impl_item: \
trait_generics={:?} \
@@ -729,23 +837,56 @@ fn check_region_bounds_on_impl_item<'tcx>(
.get_generics(impl_m.def_id.expect_local())
.expect("expected impl item to have generics or else we can't compare them")
.span;
- let generics_span = if let Some(local_def_id) = trait_m.def_id.as_local() {
- Some(
- tcx.hir()
- .get_generics(local_def_id)
- .expect("expected trait item to have generics or else we can't compare them")
- .span,
- )
- } else {
- None
- };
- let reported = tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait {
- span,
- item_kind: assoc_item_kind_str(impl_m),
- ident: impl_m.ident(tcx),
- generics_span,
- });
+ let mut generics_span = None;
+ let mut bounds_span = vec![];
+ let mut where_span = None;
+ if let Some(trait_node) = tcx.hir().get_if_local(trait_m.def_id)
+ && let Some(trait_generics) = trait_node.generics()
+ {
+ generics_span = Some(trait_generics.span);
+ // FIXME: we could potentially look at the impl's bounds to not point at bounds that
+ // *are* present in the impl.
+ for p in trait_generics.predicates {
+ if let hir::WherePredicate::BoundPredicate(pred) = p {
+ for b in pred.bounds {
+ if let hir::GenericBound::Outlives(lt) = b {
+ bounds_span.push(lt.ident.span);
+ }
+ }
+ }
+ }
+ if let Some(impl_node) = tcx.hir().get_if_local(impl_m.def_id)
+ && let Some(impl_generics) = impl_node.generics()
+ {
+ let mut impl_bounds = 0;
+ for p in impl_generics.predicates {
+ if let hir::WherePredicate::BoundPredicate(pred) = p {
+ for b in pred.bounds {
+ if let hir::GenericBound::Outlives(_) = b {
+ impl_bounds += 1;
+ }
+ }
+ }
+ }
+ if impl_bounds == bounds_span.len() {
+ bounds_span = vec![];
+ } else if impl_generics.has_where_clause_predicates {
+ where_span = Some(impl_generics.where_clause_span);
+ }
+ }
+ }
+ let reported = tcx
+ .sess
+ .create_err(LifetimesOrBoundsMismatchOnTrait {
+ span,
+ item_kind: assoc_item_kind_str(impl_m),
+ ident: impl_m.ident(tcx),
+ generics_span,
+ bounds_span,
+ where_span,
+ })
+ .emit_unless(delay);
return Err(reported);
}
@@ -891,9 +1032,9 @@ fn compare_self_type<'tcx>(
fn compare_number_of_generics<'tcx>(
tcx: TyCtxt<'tcx>,
impl_: &ty::AssocItem,
- _impl_span: Span,
trait_: &ty::AssocItem,
trait_span: Option<Span>,
+ delay: bool,
) -> Result<(), ErrorGuaranteed> {
let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();
let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts();
@@ -1023,7 +1164,7 @@ fn compare_number_of_generics<'tcx>(
err.span_label(*span, "`impl Trait` introduces an implicit type parameter");
}
- let reported = err.emit();
+ let reported = err.emit_unless(delay);
err_occurred = Some(reported);
}
}
@@ -1275,6 +1416,7 @@ fn compare_generic_param_kinds<'tcx>(
tcx: TyCtxt<'tcx>,
impl_item: &ty::AssocItem,
trait_item: &ty::AssocItem,
+ delay: bool,
) -> Result<(), ErrorGuaranteed> {
assert_eq!(impl_item.kind, trait_item.kind);
@@ -1332,7 +1474,7 @@ fn compare_generic_param_kinds<'tcx>(
err.span_label(impl_header_span, "");
err.span_label(param_impl_span, make_param_message("found", param_impl));
- let reported = err.emit();
+ let reported = err.emit_unless(delay);
return Err(reported);
}
}
@@ -1381,18 +1523,15 @@ pub(crate) fn raw_compare_const_impl<'tcx>(
);
// There is no "body" here, so just pass dummy id.
- let impl_ty = ocx.normalize(cause.clone(), param_env, impl_ty);
+ let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
debug!("compare_const_impl: impl_ty={:?}", impl_ty);
- let trait_ty = ocx.normalize(cause.clone(), param_env, trait_ty);
+ let trait_ty = ocx.normalize(&cause, param_env, trait_ty);
debug!("compare_const_impl: trait_ty={:?}", trait_ty);
- let err = infcx
- .at(&cause, param_env)
- .sup(trait_ty, impl_ty)
- .map(|ok| ocx.register_infer_ok_obligations(ok));
+ let err = ocx.sup(&cause, param_env, trait_ty, impl_ty);
if let Err(terr) = err {
debug!(
@@ -1441,7 +1580,7 @@ pub(crate) fn raw_compare_const_impl<'tcx>(
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None, false));
+ return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None));
}
// FIXME return `ErrorReported` if region obligations error?
@@ -1461,9 +1600,9 @@ pub(crate) fn compare_ty_impl<'tcx>(
debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref);
let _: Result<(), ErrorGuaranteed> = (|| {
- compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?;
+ compare_number_of_generics(tcx, impl_ty, trait_ty, trait_item_span, false)?;
- compare_generic_param_kinds(tcx, impl_ty, trait_ty)?;
+ compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?;
let sp = tcx.def_span(impl_ty.def_id);
compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
@@ -1485,18 +1624,10 @@ fn compare_type_predicate_entailment<'tcx>(
let trait_to_impl_substs =
impl_substs.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.substs);
- let impl_ty_generics = tcx.generics_of(impl_ty.def_id);
- let trait_ty_generics = tcx.generics_of(trait_ty.def_id);
let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id);
let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id);
- check_region_bounds_on_impl_item(
- tcx,
- impl_ty,
- trait_ty,
- &trait_ty_generics,
- &impl_ty_generics,
- )?;
+ check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?;
let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs);
@@ -1533,14 +1664,11 @@ fn compare_type_predicate_entailment<'tcx>(
debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
- let mut selcx = traits::SelectionContext::new(&infcx);
-
assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
{
let cause = ObligationCause::misc(span, impl_ty_hir_id);
- let traits::Normalized { value: predicate, obligations } =
- traits::normalize(&mut selcx, param_env, cause, predicate);
+ let predicate = ocx.normalize(&cause, param_env, predicate);
let cause = ObligationCause::new(
span,
@@ -1551,15 +1679,14 @@ fn compare_type_predicate_entailment<'tcx>(
kind: impl_ty.kind,
},
);
- ocx.register_obligations(obligations);
- ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
+ ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
}
// Check that all obligations are satisfied by the implementation's
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return Err(reported);
}
@@ -1665,13 +1792,10 @@ pub fn check_type_bounds<'tcx>(
GenericParamDefKind::Const { .. } => {
let bound_var = ty::BoundVariableKind::Const;
bound_vars.push(bound_var);
- tcx.mk_const(ty::ConstS {
- ty: tcx.type_of(param.def_id),
- kind: ty::ConstKind::Bound(
- ty::INNERMOST,
- ty::BoundVar::from_usize(bound_vars.len() - 1),
- ),
- })
+ tcx.mk_const(
+ ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1)),
+ tcx.type_of(param.def_id),
+ )
.into()
}
});
@@ -1737,7 +1861,6 @@ pub fn check_type_bounds<'tcx>(
let assumed_wf_types =
ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local());
- let mut selcx = traits::SelectionContext::new(&infcx);
let normalize_cause = ObligationCause::new(
impl_ty_span,
impl_ty_hir_id,
@@ -1760,29 +1883,24 @@ pub fn check_type_bounds<'tcx>(
.subst_iter_copied(tcx, rebased_substs)
.map(|(concrete_ty_bound, span)| {
debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
- traits::Obligation::new(mk_cause(span), param_env, concrete_ty_bound)
+ traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
})
.collect();
debug!("check_type_bounds: item_bounds={:?}", obligations);
for mut obligation in util::elaborate_obligations(tcx, obligations) {
- let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
- &mut selcx,
- normalize_param_env,
- normalize_cause.clone(),
- obligation.predicate,
- );
+ let normalized_predicate =
+ ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate);
debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
obligation.predicate = normalized_predicate;
- ocx.register_obligations(obligations);
ocx.register_obligation(obligation);
}
// Check that all obligations are satisfied by the implementation's
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return Err(reported);
}
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index a74016e22..d6e3ddb0a 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -183,19 +183,27 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
let predicate = predicate.kind();
let p = p.kind();
match (predicate.skip_binder(), p.skip_binder()) {
- (ty::PredicateKind::Trait(a), ty::PredicateKind::Trait(b)) => {
- relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
- }
- (ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => {
- relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
- }
+ (
+ ty::PredicateKind::Clause(ty::Clause::Trait(a)),
+ ty::PredicateKind::Clause(ty::Clause::Trait(b)),
+ ) => relator.relate(predicate.rebind(a), p.rebind(b)).is_ok(),
+ (
+ ty::PredicateKind::Clause(ty::Clause::Projection(a)),
+ ty::PredicateKind::Clause(ty::Clause::Projection(b)),
+ ) => relator.relate(predicate.rebind(a), p.rebind(b)).is_ok(),
(
ty::PredicateKind::ConstEvaluatable(a),
ty::PredicateKind::ConstEvaluatable(b),
) => relator.relate(predicate.rebind(a), predicate.rebind(b)).is_ok(),
(
- ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)),
- ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)),
+ ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
+ ty_a,
+ lt_a,
+ ))),
+ ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
+ ty_b,
+ lt_b,
+ ))),
) => {
relator.relate(predicate.rebind(ty_a), p.rebind(ty_b)).is_ok()
&& relator.relate(predicate.rebind(lt_a), p.rebind(lt_b)).is_ok()
@@ -225,9 +233,10 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
result
}
-// This is an implementation of the TypeRelation trait with the
-// aim of simply comparing for equality (without side-effects).
-// It is not intended to be used anywhere else other than here.
+/// This is an implementation of the [`TypeRelation`] trait with the
+/// aim of simply comparing for equality (without side-effects).
+///
+/// It is not intended to be used anywhere else other than here.
pub(crate) struct SimpleEqRelation<'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -244,6 +253,10 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
self.tcx
}
+ fn intercrate(&self) -> bool {
+ false
+ }
+
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
}
@@ -256,6 +269,10 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
true
}
+ fn mark_ambiguous(&mut self) {
+ bug!()
+ }
+
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 609095c9c..69e54b41d 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -134,15 +134,18 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
let name_str = intrinsic_name.as_str();
let bound_vars = tcx.mk_bound_variable_kinds(
- [ty::BoundVariableKind::Region(ty::BrAnon(0)), ty::BoundVariableKind::Region(ty::BrEnv)]
- .iter()
- .copied(),
+ [
+ ty::BoundVariableKind::Region(ty::BrAnon(0, None)),
+ ty::BoundVariableKind::Region(ty::BrEnv),
+ ]
+ .iter()
+ .copied(),
);
let mk_va_list_ty = |mutbl| {
tcx.lang_items().va_list().map(|did| {
let region = tcx.mk_region(ty::ReLateBound(
ty::INNERMOST,
- ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) },
+ ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) },
));
let env_region = tcx.mk_region(ty::ReLateBound(
ty::INNERMOST,
@@ -364,7 +367,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
);
let discriminant_def_id = assoc_items[0];
- let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) };
+ let br =
+ ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) };
(
1,
vec![
@@ -418,7 +422,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
sym::raw_eq => {
- let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) };
+ let br =
+ ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) };
let param_ty =
tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)), param(0));
(1, vec![param_ty; 2], tcx.types.bool)
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 2e7b10257..29255472a 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -159,7 +159,7 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
// the consumer's responsibility to ensure all bytes that have been read
// have defined values.
if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
- && alloc.inner().provenance().len() != 0
+ && alloc.inner().provenance().ptrs().len() != 0
{
let msg = "statics with a custom `#[link_section]` must be a \
simple list of bytes on the wasm target with no \
@@ -309,7 +309,7 @@ fn bounds_from_generic_predicates<'tcx>(
debug!("predicate {:?}", predicate);
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(trait_predicate) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
let entry = types.entry(trait_predicate.self_ty()).or_default();
let def_id = trait_predicate.def_id();
if Some(def_id) != tcx.lang_items().sized_trait() {
@@ -318,7 +318,7 @@ fn bounds_from_generic_predicates<'tcx>(
entry.push(trait_predicate.def_id());
}
}
- ty::PredicateKind::Projection(projection_pred) => {
+ ty::PredicateKind::Clause(ty::Clause::Projection(projection_pred)) => {
projections.push(bound_predicate.rebind(projection_pred));
}
_ => {}
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index ff32329e4..b315ebad4 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -241,17 +241,46 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
// scopes, meaning that temporaries cannot outlive them.
// This ensures fixed size stacks.
hir::ExprKind::Binary(
- source_map::Spanned { node: hir::BinOpKind::And, .. },
- _,
- ref r,
- )
- | hir::ExprKind::Binary(
- source_map::Spanned { node: hir::BinOpKind::Or, .. },
- _,
+ source_map::Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
+ ref l,
ref r,
) => {
- // For shortcircuiting operators, mark the RHS as a terminating
- // scope since it only executes conditionally.
+ // expr is a short circuiting operator (|| or &&). As its
+ // functionality can't be overridden by traits, it always
+ // processes bool sub-expressions. bools are Copy and thus we
+ // can drop any temporaries in evaluation (read) order
+ // (with the exception of potentially failing let expressions).
+ // We achieve this by enclosing the operands in a terminating
+ // scope, both the LHS and the RHS.
+
+ // We optimize this a little in the presence of chains.
+ // Chains like a && b && c get lowered to AND(AND(a, b), c).
+ // In here, b and c are RHS, while a is the only LHS operand in
+ // that chain. This holds true for longer chains as well: the
+ // leading operand is always the only LHS operand that is not a
+ // binop itself. Putting a binop like AND(a, b) into a
+ // terminating scope is not useful, thus we only put the LHS
+ // into a terminating scope if it is not a binop.
+
+ let terminate_lhs = match l.kind {
+ // let expressions can create temporaries that live on
+ hir::ExprKind::Let(_) => false,
+ // binops already drop their temporaries, so there is no
+ // need to put them into a terminating scope.
+ // This is purely an optimization to reduce the number of
+ // terminating scopes.
+ hir::ExprKind::Binary(
+ source_map::Spanned {
+ node: hir::BinOpKind::And | hir::BinOpKind::Or, ..
+ },
+ ..,
+ ) => false,
+ // otherwise: mark it as terminating
+ _ => true,
+ };
+ if terminate_lhs {
+ terminating(l.hir_id.local_id);
+ }
// `Let` expressions (in a let-chain) shouldn't be terminating, as their temporaries
// should live beyond the immediate expression
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index a23575004..b065ace6b 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1,7 +1,7 @@
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
use hir::def::DefKind;
use rustc_ast as ast;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -14,13 +14,14 @@ use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{
- self, AdtKind, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable,
- TypeSuperVisitable, TypeVisitable, TypeVisitor,
+ self, AdtKind, DefIdTree, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
+ TypeVisitable, TypeVisitor,
};
use rustc_middle::ty::{GenericArgKind, InternalSubsts};
use rustc_session::parse::feature_err;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
+use rustc_target::spec::abi::Abi;
use rustc_trait_selection::autoderef::Autoderef;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
@@ -52,12 +53,14 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
self.ocx.infcx.tcx
}
+ // Convenience function to normalize during wfcheck. This performs
+ // `ObligationCtxt::normalize`, but provides a nice `ObligationCauseCode`.
fn normalize<T>(&self, span: Span, loc: Option<WellFormedLoc>, value: T) -> T
where
T: TypeFoldable<'tcx>,
{
self.ocx.normalize(
- ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc)),
+ &ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc)),
self.param_env,
value,
)
@@ -74,9 +77,10 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
// for a type to be WF, we do not need to check if const trait predicates satisfy.
let param_env = self.param_env.without_const();
self.ocx.register_obligation(traits::Obligation::new(
+ self.tcx(),
cause,
param_env,
- ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx()),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)),
));
}
}
@@ -104,7 +108,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
f(&mut wfcx);
let errors = wfcx.select_all_or_error();
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return;
}
@@ -116,7 +120,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
}
fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
- let node = tcx.hir().expect_owner(def_id);
+ let node = tcx.hir().owner(def_id);
match node {
hir::OwnerNode::Crate(_) => {}
hir::OwnerNode::Item(item) => check_item(tcx, item),
@@ -218,19 +222,16 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
hir::ItemKind::Const(ty, ..) => {
check_item_type(tcx, def_id, ty.span, false);
}
- hir::ItemKind::Struct(ref struct_def, ref ast_generics) => {
- check_type_defn(tcx, item, false, |wfcx| vec![wfcx.non_enum_variant(struct_def)]);
-
+ hir::ItemKind::Struct(_, ref ast_generics) => {
+ check_type_defn(tcx, item, false);
check_variances_for_type_defn(tcx, item, ast_generics);
}
- hir::ItemKind::Union(ref struct_def, ref ast_generics) => {
- check_type_defn(tcx, item, true, |wfcx| vec![wfcx.non_enum_variant(struct_def)]);
-
+ hir::ItemKind::Union(_, ref ast_generics) => {
+ check_type_defn(tcx, item, true);
check_variances_for_type_defn(tcx, item, ast_generics);
}
- hir::ItemKind::Enum(ref enum_def, ref ast_generics) => {
- check_type_defn(tcx, item, true, |wfcx| wfcx.enum_variants(enum_def));
-
+ hir::ItemKind::Enum(_, ref ast_generics) => {
+ check_type_defn(tcx, item, true);
check_variances_for_type_defn(tcx, item, ast_generics);
}
hir::ItemKind::Trait(..) => {
@@ -414,7 +415,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
.iter()
.copied()
.collect::<Vec<_>>(),
- &FxHashSet::default(),
+ &FxIndexSet::default(),
gat_def_id.def_id,
gat_generics,
)
@@ -463,12 +464,16 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
let mut unsatisfied_bounds: Vec<_> = required_bounds
.into_iter()
.filter(|clause| match clause.kind().skip_binder() {
- ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
- !region_known_to_outlive(tcx, gat_hir, param_env, &FxHashSet::default(), a, b)
- }
- ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
- !ty_known_to_outlive(tcx, gat_hir, param_env, &FxHashSet::default(), a, b)
+ ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(
+ a,
+ b,
+ ))) => {
+ !region_known_to_outlive(tcx, gat_hir, param_env, &FxIndexSet::default(), a, b)
}
+ ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
+ a,
+ b,
+ ))) => !ty_known_to_outlive(tcx, gat_hir, param_env, &FxIndexSet::default(), a, b),
_ => bug!("Unexpected PredicateKind"),
})
.map(|clause| clause.to_string())
@@ -549,7 +554,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>(
param_env: ty::ParamEnv<'tcx>,
item_hir: hir::HirId,
to_check: T,
- wf_tys: &FxHashSet<Ty<'tcx>>,
+ wf_tys: &FxIndexSet<Ty<'tcx>>,
gat_def_id: LocalDefId,
gat_generics: &'tcx ty::Generics,
) -> Option<FxHashSet<ty::Predicate<'tcx>>> {
@@ -600,8 +605,9 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>(
}));
// The predicate we expect to see. (In our example,
// `Self: 'me`.)
- let clause =
- ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_param, region_param));
+ let clause = ty::PredicateKind::Clause(ty::Clause::TypeOutlives(
+ ty::OutlivesPredicate(ty_param, region_param),
+ ));
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
bounds.insert(clause);
}
@@ -637,9 +643,8 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>(
name: region_b_param.name,
}));
// The predicate we expect to see.
- let clause = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
- region_a_param,
- region_b_param,
+ let clause = ty::PredicateKind::Clause(ty::Clause::RegionOutlives(
+ ty::OutlivesPredicate(region_a_param, region_b_param),
));
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
bounds.insert(clause);
@@ -656,7 +661,7 @@ fn ty_known_to_outlive<'tcx>(
tcx: TyCtxt<'tcx>,
id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
- wf_tys: &FxHashSet<Ty<'tcx>>,
+ wf_tys: &FxIndexSet<Ty<'tcx>>,
ty: Ty<'tcx>,
region: ty::Region<'tcx>,
) -> bool {
@@ -673,7 +678,7 @@ fn region_known_to_outlive<'tcx>(
tcx: TyCtxt<'tcx>,
id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
- wf_tys: &FxHashSet<Ty<'tcx>>,
+ wf_tys: &FxIndexSet<Ty<'tcx>>,
region_a: ty::Region<'tcx>,
region_b: ty::Region<'tcx>,
) -> bool {
@@ -697,7 +702,7 @@ fn resolve_regions_with_wf_tys<'tcx>(
tcx: TyCtxt<'tcx>,
id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
- wf_tys: &FxHashSet<Ty<'tcx>>,
+ wf_tys: &FxIndexSet<Ty<'tcx>>,
add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'tcx>, &'a RegionBoundPairs<'tcx>),
) -> bool {
// Unfortunately, we have to use a new `InferCtxt` each call, because
@@ -855,7 +860,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
// Const parameters are well formed if their type is structural match.
hir::GenericParamKind::Const { ty: hir_ty, default: _ } => {
- let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
+ let ty = tcx.type_of(param.def_id);
if tcx.features().adt_const_params {
if let Some(non_structural_match_ty) =
@@ -1037,27 +1042,25 @@ 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, F>(
- tcx: TyCtxt<'tcx>,
- item: &hir::Item<'tcx>,
- all_sized: bool,
- mut lookup_fields: F,
-) where
- F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec<AdtVariant<'tcx>>,
-{
+fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: bool) {
let _ = tcx.representability(item.owner_id.def_id);
+ let adt_def = tcx.adt_def(item.owner_id);
enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
- let variants = lookup_fields(wfcx);
- let packed = tcx.adt_def(item.owner_id).repr().packed();
+ let variants = adt_def.variants();
+ let packed = adt_def.repr().packed();
- for variant in &variants {
+ for variant in variants.iter() {
// All field types must be well-formed.
for field in &variant.fields {
+ let field_id = field.did.expect_local();
+ let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id)
+ else { bug!() };
+ let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did));
wfcx.register_wf_obligation(
- field.span,
- Some(WellFormedLoc::Ty(field.def_id)),
- field.ty.into(),
+ hir_ty.span,
+ Some(WellFormedLoc::Ty(field_id)),
+ ty.into(),
)
}
@@ -1065,7 +1068,7 @@ fn check_type_defn<'tcx, F>(
// intermediate types must be sized.
let needs_drop_copy = || {
packed && {
- let ty = variant.fields.last().unwrap().ty;
+ let ty = tcx.type_of(variant.fields.last().unwrap().did);
let ty = tcx.erase_regions(ty);
if ty.needs_infer() {
tcx.sess
@@ -1084,39 +1087,43 @@ fn check_type_defn<'tcx, F>(
variant.fields[..variant.fields.len() - unsized_len].iter().enumerate()
{
let last = idx == variant.fields.len() - 1;
+ let field_id = field.did.expect_local();
+ let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id)
+ else { bug!() };
+ let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did));
wfcx.register_bound(
traits::ObligationCause::new(
- field.span,
+ hir_ty.span,
wfcx.body_id,
traits::FieldSized {
adt_kind: match item_adt_kind(&item.kind) {
Some(i) => i,
None => bug!(),
},
- span: field.span,
+ span: hir_ty.span,
last,
},
),
wfcx.param_env,
- field.ty,
+ ty,
tcx.require_lang_item(LangItem::Sized, None),
);
}
// Explicit `enum` discriminant values must const-evaluate successfully.
- if let Some(discr_def_id) = variant.explicit_discr {
+ if let ty::VariantDiscr::Explicit(discr_def_id) = variant.discr {
let cause = traits::ObligationCause::new(
tcx.def_span(discr_def_id),
wfcx.body_id,
traits::MiscObligation,
);
wfcx.register_obligation(traits::Obligation::new(
+ tcx,
cause,
wfcx.param_env,
ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
- ty::Const::from_anon_const(tcx, discr_def_id),
- ))
- .to_predicate(tcx),
+ ty::Const::from_anon_const(tcx, discr_def_id.expect_local()),
+ )),
));
}
}
@@ -1453,7 +1460,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
wfcx.body_id,
traits::ItemObligation(def_id.to_def_id()),
);
- traits::Obligation::new(cause, wfcx.param_env, pred)
+ traits::Obligation::new(tcx, cause, wfcx.param_env, pred)
});
let predicates = predicates.0.instantiate_identity(tcx);
@@ -1537,23 +1544,50 @@ fn check_fn_or_method<'tcx>(
check_where_clauses(wfcx, span, def_id);
check_return_position_impl_trait_in_trait_bounds(
- tcx,
wfcx,
def_id,
sig.output(),
hir_decl.output.span(),
);
+
+ if sig.abi == Abi::RustCall {
+ let span = tcx.def_span(def_id);
+ let has_implicit_self = hir_decl.implicit_self != hir::ImplicitSelfKind::None;
+ let mut inputs = sig.inputs().iter().skip(if has_implicit_self { 1 } else { 0 });
+ // Check that the argument is a tuple
+ if let Some(ty) = inputs.next() {
+ wfcx.register_bound(
+ ObligationCause::new(span, wfcx.body_id, ObligationCauseCode::RustCall),
+ wfcx.param_env,
+ *ty,
+ tcx.require_lang_item(hir::LangItem::Tuple, Some(span)),
+ );
+ } else {
+ tcx.sess.span_err(
+ hir_decl.inputs.last().map_or(span, |input| input.span),
+ "functions with the \"rust-call\" ABI must take a single non-self tuple argument",
+ );
+ }
+ // No more inputs other than the `self` type and the tuple type
+ if inputs.next().is_some() {
+ tcx.sess.span_err(
+ hir_decl.inputs.last().map_or(span, |input| input.span),
+ "functions with the \"rust-call\" ABI must take a single non-self tuple argument",
+ );
+ }
+ }
}
/// Basically `check_associated_type_bounds`, but separated for now and should be
/// deduplicated when RPITITs get lowered into real associated items.
+#[tracing::instrument(level = "trace", skip(wfcx))]
fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
- tcx: TyCtxt<'tcx>,
wfcx: &WfCheckingCtxt<'_, 'tcx>,
fn_def_id: LocalDefId,
fn_output: Ty<'tcx>,
span: Span,
) {
+ let tcx = wfcx.tcx();
if let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id())
&& assoc_item.container == ty::AssocItemContainer::TraitContainer
{
@@ -1563,8 +1597,10 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
&& tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
&& tcx.impl_trait_in_trait_parent(proj.item_def_id) == fn_def_id.to_def_id()
{
+ let span = tcx.def_span(proj.item_def_id);
let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id);
let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
+ let bound = ty::EarlyBinder(bound).subst(tcx, proj.substs);
let normalized_bound = wfcx.normalize(span, None, bound);
traits::wf::predicate_obligations(
wfcx.infcx,
@@ -1675,14 +1711,13 @@ fn receiver_is_valid<'tcx>(
// `self: Self` is always valid.
if can_eq_self(receiver_ty) {
- if let Err(err) = wfcx.equate_types(&cause, wfcx.param_env, self_ty, receiver_ty) {
+ if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, receiver_ty) {
infcx.err_ctxt().report_mismatched_types(&cause, self_ty, receiver_ty, err).emit();
}
return true;
}
- let mut autoderef =
- Autoderef::new(infcx, wfcx.param_env, wfcx.body_id, span, receiver_ty, span);
+ let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_id, span, receiver_ty);
// The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`.
if arbitrary_self_types_enabled {
@@ -1692,7 +1727,7 @@ fn receiver_is_valid<'tcx>(
// The first type is `receiver_ty`, which we know its not equal to `self_ty`; skip it.
autoderef.next();
- let receiver_trait_def_id = tcx.require_lang_item(LangItem::Receiver, None);
+ let receiver_trait_def_id = tcx.require_lang_item(LangItem::Receiver, Some(span));
// Keep dereferencing `receiver_ty` until we get to `self_ty`.
loop {
@@ -1705,9 +1740,7 @@ fn receiver_is_valid<'tcx>(
if can_eq_self(potential_self_ty) {
wfcx.register_obligations(autoderef.into_obligations());
- if let Err(err) =
- wfcx.equate_types(&cause, wfcx.param_env, self_ty, potential_self_ty)
- {
+ if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty) {
infcx
.err_ctxt()
.report_mismatched_types(&cause, self_ty, potential_self_ty, err)
@@ -1754,13 +1787,9 @@ fn receiver_is_implemented<'tcx>(
receiver_ty: Ty<'tcx>,
) -> bool {
let tcx = wfcx.tcx();
- let trait_ref = ty::Binder::dummy(ty::TraitRef {
- def_id: receiver_trait_def_id,
- substs: tcx.mk_substs_trait(receiver_ty, &[]),
- });
+ let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(receiver_trait_def_id, [receiver_ty]));
- let obligation =
- traits::Obligation::new(cause, wfcx.param_env, trait_ref.without_const().to_predicate(tcx));
+ let obligation = traits::Obligation::new(tcx, cause, wfcx.param_env, trait_ref);
if wfcx.infcx.predicate_must_hold_modulo_regions(&obligation) {
true
@@ -1907,6 +1936,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
}
let obligation = traits::Obligation::new(
+ tcx,
traits::ObligationCause::new(span, self.body_id, traits::TrivialBound),
empty_env,
pred,
@@ -1925,56 +1955,6 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalDefId) {
items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id));
}
-///////////////////////////////////////////////////////////////////////////
-// ADT
-
-// FIXME(eddyb) replace this with getting fields/discriminants through `ty::AdtDef`.
-struct AdtVariant<'tcx> {
- /// Types of fields in the variant, that must be well-formed.
- fields: Vec<AdtField<'tcx>>,
-
- /// Explicit discriminant of this variant (e.g. `A = 123`),
- /// that must evaluate to a constant value.
- explicit_discr: Option<LocalDefId>,
-}
-
-struct AdtField<'tcx> {
- ty: Ty<'tcx>,
- def_id: LocalDefId,
- span: Span,
-}
-
-impl<'a, 'tcx> WfCheckingCtxt<'a, 'tcx> {
- // FIXME(eddyb) replace this with getting fields through `ty::AdtDef`.
- fn non_enum_variant(&self, struct_def: &hir::VariantData<'_>) -> AdtVariant<'tcx> {
- let fields = struct_def
- .fields()
- .iter()
- .map(|field| {
- let def_id = self.tcx().hir().local_def_id(field.hir_id);
- let field_ty = self.tcx().type_of(def_id);
- let field_ty = self.normalize(field.ty.span, None, field_ty);
- debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty);
- AdtField { ty: field_ty, span: field.ty.span, def_id }
- })
- .collect();
- AdtVariant { fields, explicit_discr: None }
- }
-
- fn enum_variants(&self, enum_def: &hir::EnumDef<'_>) -> Vec<AdtVariant<'tcx>> {
- enum_def
- .variants
- .iter()
- .map(|variant| AdtVariant {
- fields: self.non_enum_variant(&variant.data).fields,
- explicit_discr: variant
- .disr_expr
- .map(|explicit_discr| self.tcx().hir().local_def_id(explicit_discr.hir_id)),
- })
- .collect()
- }
-}
-
fn error_392(
tcx: TyCtxt<'_>,
span: Span,
diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs
index d0c317334..5749b0478 100644
--- a/compiler/rustc_hir_analysis/src/check_unused.rs
+++ b/compiler/rustc_hir_analysis/src/check_unused.rs
@@ -57,25 +57,6 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
.maybe_unused_extern_crates(())
.iter()
.filter(|&&(def_id, _)| {
- // The `def_id` here actually was calculated during resolution (at least
- // at the time of this writing) and is being shipped to us via a side
- // channel of the tcx. There may have been extra expansion phases,
- // however, which ended up removing the `def_id` *after* expansion.
- //
- // As a result we need to verify that `def_id` is indeed still valid for
- // our AST and actually present in the HIR map. If it's not there then
- // there's safely nothing to warn about, and otherwise we carry on with
- // our execution.
- //
- // Note that if we carry through to the `extern_mod_stmt_cnum` query
- // below it'll cause a panic because `def_id` is actually bogus at this
- // point in time otherwise.
- if tcx.hir().find(tcx.hir().local_def_id_to_hir_id(def_id)).is_none() {
- return false;
- }
- true
- })
- .filter(|&&(def_id, _)| {
tcx.extern_mod_stmt_cnum(def_id).map_or(true, |cnum| {
!tcx.is_compiler_builtins(cnum)
&& !tcx.is_panic_runtime(cnum)
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index b6c91d425..193ecdb16 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -114,7 +114,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
traits::ObligationCause::dummy_with_span(field_ty_span),
param_env,
ty,
- tcx.lang_items().copy_trait().unwrap(),
+ tcx.require_lang_item(LangItem::Copy, Some(span)),
) {
let error_predicate = error.obligation.predicate;
// Only note if it's not the root obligation, otherwise it's trivial and
@@ -128,11 +128,11 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
.or_default()
.push(error.obligation.cause.span);
}
- if let ty::PredicateKind::Trait(ty::TraitPredicate {
+ if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
trait_ref,
polarity: ty::ImplPolarity::Positive,
..
- }) = error_predicate.kind().skip_binder()
+ })) = error_predicate.kind().skip_binder()
{
let ty = trait_ref.self_ty();
if let ty::Param(_) = ty.kind() {
@@ -315,13 +315,12 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
cause.clone(),
dispatch_from_dyn_trait,
0,
- field.ty(tcx, substs_a),
- &[field.ty(tcx, substs_b).into()],
+ [field.ty(tcx, substs_a), field.ty(tcx, substs_b)],
)
}),
);
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None);
}
// Finally, resolve all regions.
@@ -371,7 +370,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
mt_b: ty::TypeAndMut<'tcx>,
mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
- if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) {
+ if mt_a.mutbl < mt_b.mutbl {
infcx
.err_ctxt()
.report_mismatched_types(
@@ -558,10 +557,10 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
// Register an obligation for `A: Trait<B>`.
let cause = traits::ObligationCause::misc(span, impl_hir_id);
let predicate =
- predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, source, &[target.into()]);
+ predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, [source, target]);
let errors = traits::fully_solve_obligation(&infcx, predicate);
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None);
}
// Finally, resolve all regions.
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index ae9ebe590..1bf3768fe 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -5,10 +5,11 @@
// done by the orphan and overlap modules. Then we build up various
// mappings. That mapping code resides here.
-use rustc_errors::struct_span_err;
+use rustc_errors::{error_code, struct_span_err};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
+use rustc_span::sym;
use rustc_trait_selection::traits;
mod builtin;
@@ -39,61 +40,26 @@ fn enforce_trait_manually_implementable(
impl_def_id: LocalDefId,
trait_def_id: DefId,
) {
- let did = Some(trait_def_id);
- let li = tcx.lang_items();
let impl_header_span = tcx.def_span(impl_def_id);
- // Disallow *all* explicit impls of `Pointee`, `DiscriminantKind`, `Sized` and `Unsize` for now.
- if did == li.pointee_trait() {
- struct_span_err!(
+ // Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]`
+ if tcx.has_attr(trait_def_id, sym::rustc_deny_explicit_impl) {
+ let trait_name = tcx.item_name(trait_def_id);
+ let mut err = struct_span_err!(
tcx.sess,
impl_header_span,
E0322,
- "explicit impls for the `Pointee` trait are not permitted"
- )
- .span_label(impl_header_span, "impl of `Pointee` not allowed")
- .emit();
- return;
- }
-
- if did == li.discriminant_kind_trait() {
- struct_span_err!(
- tcx.sess,
- impl_header_span,
- E0322,
- "explicit impls for the `DiscriminantKind` trait are not permitted"
- )
- .span_label(impl_header_span, "impl of `DiscriminantKind` not allowed")
- .emit();
- return;
- }
-
- if did == li.sized_trait() {
- struct_span_err!(
- tcx.sess,
- impl_header_span,
- E0322,
- "explicit impls for the `Sized` trait are not permitted"
- )
- .span_label(impl_header_span, "impl of `Sized` not allowed")
- .emit();
- return;
- }
-
- if did == li.unsize_trait() {
- struct_span_err!(
- tcx.sess,
- impl_header_span,
- E0328,
- "explicit impls for the `Unsize` trait are not permitted"
- )
- .span_label(impl_header_span, "impl of `Unsize` not allowed")
- .emit();
- return;
- }
+ "explicit impls for the `{trait_name}` trait are not permitted"
+ );
+ err.span_label(impl_header_span, format!("impl of `{trait_name}` not allowed"));
+
+ // Maintain explicit error code for `Unsize`, since it has a useful
+ // explanation about using `CoerceUnsized` instead.
+ if Some(trait_def_id) == tcx.lang_items().unsize_trait() {
+ err.code(error_code!(E0328));
+ }
- if tcx.features().unboxed_closures {
- // the feature gate allows all Fn traits
+ err.emit();
return;
}
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index bb45c3823..cc5114dba 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -5,7 +5,6 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{struct_span_err, DelayDm};
use rustc_errors::{Diagnostic, ErrorGuaranteed};
use rustc_hir as hir;
-use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::IgnoreRegions;
use rustc_middle::ty::{
@@ -23,9 +22,7 @@ pub(crate) fn orphan_check_impl(
impl_def_id: LocalDefId,
) -> Result<(), ErrorGuaranteed> {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
- if let Some(err) = trait_ref.error_reported() {
- return Err(err);
- }
+ trait_ref.error_reported()?;
let ret = do_orphan_check_impl(tcx, trait_ref, impl_def_id);
if tcx.trait_is_auto(trait_ref.def_id) {
@@ -49,58 +46,6 @@ fn do_orphan_check_impl<'tcx>(
let sp = tcx.def_span(def_id);
let tr = impl_.of_trait.as_ref().unwrap();
- // Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples,
- // and #84660 where it would otherwise allow unsoundness.
- if trait_ref.has_opaque_types() {
- trace!("{:#?}", item);
- // First we find the opaque type in question.
- for ty in trait_ref.substs {
- for ty in ty.walk() {
- let ty::subst::GenericArgKind::Type(ty) = ty.unpack() else { continue };
- let ty::Opaque(def_id, _) = *ty.kind() else { continue };
- trace!(?def_id);
-
- // Then we search for mentions of the opaque type's type alias in the HIR
- struct SpanFinder<'tcx> {
- sp: Span,
- def_id: DefId,
- tcx: TyCtxt<'tcx>,
- }
- impl<'v, 'tcx> hir::intravisit::Visitor<'v> for SpanFinder<'tcx> {
- #[instrument(level = "trace", skip(self, _id))]
- fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
- // You can't mention an opaque type directly, so we look for type aliases
- if let hir::def::Res::Def(hir::def::DefKind::TyAlias, def_id) = path.res {
- // And check if that type alias's type contains the opaque type we're looking for
- for arg in self.tcx.type_of(def_id).walk() {
- if let GenericArgKind::Type(ty) = arg.unpack() {
- if let ty::Opaque(def_id, _) = *ty.kind() {
- if def_id == self.def_id {
- // Finally we update the span to the mention of the type alias
- self.sp = path.span;
- return;
- }
- }
- }
- }
- }
- hir::intravisit::walk_path(self, path)
- }
- }
-
- let mut visitor = SpanFinder { sp, def_id, tcx };
- hir::intravisit::walk_item(&mut visitor, item);
- let reported = tcx
- .sess
- .struct_span_err(visitor.sp, "cannot implement trait on type alias impl trait")
- .span_note(tcx.def_span(def_id), "type alias impl trait defined here")
- .emit();
- return Err(reported);
- }
- }
- span_bug!(sp, "opaque type not found, but `has_opaque_types` is set")
- }
-
match traits::orphan_check(tcx, item.owner_id.to_def_id()) {
Ok(()) => {}
Err(err) => emit_orphan_check_error(
@@ -347,7 +292,7 @@ fn emit_newtype_suggestion_for_raw_ptr(
diag: &mut Diagnostic,
) {
if !self_ty.needs_subst() {
- let mut_key = if ptr_ty.mutbl == rustc_middle::mir::Mutability::Mut { "mut " } else { "" };
+ let mut_key = ptr_ty.mutbl.prefix_str();
let msg_sugg = "consider introducing a new wrapper type".to_owned();
let sugg = vec![
(
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 346d2e2fc..1183a26d5 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -24,18 +24,16 @@ use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
use rustc_hir as hir;
-use rustc_hir::def::CtorKind;
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::weak_lang_items;
-use rustc_hir::{GenericParamKind, Node};
+use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
+use rustc_hir::{lang_items, GenericParamKind, LangItem, Node};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::mono::Linkage;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::ReprOptions;
-use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, IsSuggestable, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, IsSuggestable, ToPredicate, Ty, TyCtxt};
use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -84,6 +82,7 @@ pub fn provide(providers: &mut Providers) {
asm_target_features,
collect_mod_item_types,
should_inherit_track_caller,
+ is_type_alias_impl_trait,
..*providers
};
}
@@ -291,18 +290,15 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
match param.kind {
hir::GenericParamKind::Lifetime { .. } => {}
hir::GenericParamKind::Type { default: Some(_), .. } => {
- let def_id = self.tcx.hir().local_def_id(param.hir_id);
- self.tcx.ensure().type_of(def_id);
+ self.tcx.ensure().type_of(param.def_id);
}
hir::GenericParamKind::Type { .. } => {}
hir::GenericParamKind::Const { default, .. } => {
- let def_id = self.tcx.hir().local_def_id(param.hir_id);
- self.tcx.ensure().type_of(def_id);
+ self.tcx.ensure().type_of(param.def_id);
if let Some(default) = default {
- let default_def_id = self.tcx.hir().local_def_id(default.hir_id);
// need to store default and type of default
- self.tcx.ensure().type_of(default_def_id);
- self.tcx.ensure().const_param_default(def_id);
+ self.tcx.ensure().type_of(default.def_id);
+ self.tcx.ensure().const_param_default(param.def_id);
}
}
}
@@ -311,9 +307,9 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
}
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
- if let hir::ExprKind::Closure { .. } = expr.kind {
- let def_id = self.tcx.hir().local_def_id(expr.hir_id);
- self.tcx.ensure().generics_of(def_id);
+ if let hir::ExprKind::Closure(closure) = expr.kind {
+ self.tcx.ensure().generics_of(closure.def_id);
+ self.tcx.ensure().codegen_fn_attrs(closure.def_id);
// We do not call `type_of` for closures here as that
// depends on typecheck and would therefore hide
// any further errors in case one typeck fails.
@@ -379,8 +375,8 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
self.tcx
}
- fn item_def_id(&self) -> Option<DefId> {
- Some(self.item_def_id)
+ fn item_def_id(&self) -> DefId {
+ self.item_def_id
}
fn get_type_parameter_bounds(
@@ -512,8 +508,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
}
_ => {}
}
- err.emit();
- self.tcx().ty_error()
+ self.tcx().ty_error_with_guaranteed(err.emit())
}
}
@@ -522,7 +517,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
ty
}
- fn set_tainted_by_errors(&self) {
+ fn set_tainted_by_errors(&self, _: ErrorGuaranteed) {
// There's no obvious place to track this, so just let it go.
}
@@ -587,8 +582,12 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
tcx.ensure().type_of(item.owner_id);
tcx.ensure().predicates_of(item.owner_id);
match item.kind {
- hir::ForeignItemKind::Fn(..) => tcx.ensure().fn_sig(item.owner_id),
+ hir::ForeignItemKind::Fn(..) => {
+ tcx.ensure().codegen_fn_attrs(item.owner_id);
+ tcx.ensure().fn_sig(item.owner_id)
+ }
hir::ForeignItemKind::Static(..) => {
+ tcx.ensure().codegen_fn_attrs(item.owner_id);
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_foreign_item(item);
placeholder_type_error(
@@ -604,11 +603,11 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
}
}
}
- hir::ItemKind::Enum(ref enum_definition, _) => {
+ hir::ItemKind::Enum(..) => {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
- convert_enum_variant_types(tcx, def_id.to_def_id(), enum_definition.variants);
+ convert_enum_variant_types(tcx, def_id.to_def_id());
}
hir::ItemKind::Impl { .. } => {
tcx.ensure().generics_of(def_id);
@@ -633,23 +632,16 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
tcx.ensure().predicates_of(def_id);
for f in struct_def.fields() {
- let def_id = tcx.hir().local_def_id(f.hir_id);
- tcx.ensure().generics_of(def_id);
- tcx.ensure().type_of(def_id);
- tcx.ensure().predicates_of(def_id);
+ tcx.ensure().generics_of(f.def_id);
+ tcx.ensure().type_of(f.def_id);
+ tcx.ensure().predicates_of(f.def_id);
}
- if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
- convert_variant_ctor(tcx, ctor_hir_id);
+ if let Some(ctor_def_id) = struct_def.ctor_def_id() {
+ convert_variant_ctor(tcx, ctor_def_id);
}
}
- // Desugared from `impl Trait`, so visited by the function's return type.
- hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..),
- ..
- }) => {}
-
// Don't call `type_of` on opaque types, since that depends on type
// checking function bodies. `check_item_type` ensures that it's called
// instead.
@@ -657,27 +649,33 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
tcx.ensure().generics_of(def_id);
tcx.ensure().predicates_of(def_id);
tcx.ensure().explicit_item_bounds(def_id);
+ tcx.ensure().item_bounds(def_id);
}
- hir::ItemKind::TyAlias(..)
- | hir::ItemKind::Static(..)
- | hir::ItemKind::Const(..)
- | hir::ItemKind::Fn(..) => {
+
+ hir::ItemKind::TyAlias(..) => {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
- match it.kind {
- hir::ItemKind::Fn(..) => tcx.ensure().fn_sig(def_id),
- hir::ItemKind::OpaqueTy(..) => tcx.ensure().item_bounds(def_id),
- hir::ItemKind::Const(ty, ..) | hir::ItemKind::Static(ty, ..) => {
- if !is_suggestable_infer_ty(ty) {
- let mut visitor = HirPlaceholderCollector::default();
- visitor.visit_item(it);
- placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr());
- }
- }
- _ => (),
+ }
+
+ hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..) => {
+ tcx.ensure().generics_of(def_id);
+ tcx.ensure().type_of(def_id);
+ tcx.ensure().predicates_of(def_id);
+ if !is_suggestable_infer_ty(ty) {
+ let mut visitor = HirPlaceholderCollector::default();
+ visitor.visit_item(it);
+ placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr());
}
}
+
+ hir::ItemKind::Fn(..) => {
+ tcx.ensure().generics_of(def_id);
+ tcx.ensure().type_of(def_id);
+ tcx.ensure().predicates_of(def_id);
+ tcx.ensure().fn_sig(def_id);
+ tcx.ensure().codegen_fn_attrs(def_id);
+ }
}
}
@@ -688,6 +686,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
match trait_item.kind {
hir::TraitItemKind::Fn(..) => {
+ tcx.ensure().codegen_fn_attrs(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().fn_sig(def_id);
}
@@ -737,6 +736,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
let impl_item = tcx.hir().impl_item(impl_item_id);
match impl_item.kind {
hir::ImplItemKind::Fn(..) => {
+ tcx.ensure().codegen_fn_attrs(def_id);
tcx.ensure().fn_sig(def_id);
}
hir::ImplItemKind::Type(_) => {
@@ -750,37 +750,34 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
}
}
-fn convert_variant_ctor(tcx: TyCtxt<'_>, ctor_id: hir::HirId) {
- let def_id = tcx.hir().local_def_id(ctor_id);
+fn convert_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
}
-fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId, variants: &[hir::Variant<'_>]) {
+fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
let def = tcx.adt_def(def_id);
let repr_type = def.repr().discr_type();
let initial = repr_type.initial_discriminant(tcx);
let mut prev_discr = None::<Discr<'_>>;
// fill the discriminant values and field types
- for variant in variants {
+ for variant in def.variants() {
let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx));
prev_discr = Some(
- if let Some(ref e) = variant.disr_expr {
- let expr_did = tcx.hir().local_def_id(e.hir_id);
- def.eval_explicit_discr(tcx, expr_did.to_def_id())
+ if let ty::VariantDiscr::Explicit(const_def_id) = variant.discr {
+ def.eval_explicit_discr(tcx, const_def_id)
} else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
Some(discr)
} else {
- struct_span_err!(tcx.sess, variant.span, E0370, "enum discriminant overflowed")
- .span_label(
- variant.span,
- format!("overflowed on value after {}", prev_discr.unwrap()),
- )
+ let span = tcx.def_span(variant.def_id);
+ struct_span_err!(tcx.sess, span, E0370, "enum discriminant overflowed")
+ .span_label(span, format!("overflowed on value after {}", prev_discr.unwrap()))
.note(&format!(
"explicitly set `{} = {}` if that is desired outcome",
- variant.ident, wrapped_discr
+ tcx.item_name(variant.def_id),
+ wrapped_discr
))
.emit();
None
@@ -788,17 +785,16 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId, variants: &[hir::V
.unwrap_or(wrapped_discr),
);
- for f in variant.data.fields() {
- let def_id = tcx.hir().local_def_id(f.hir_id);
- tcx.ensure().generics_of(def_id);
- tcx.ensure().type_of(def_id);
- tcx.ensure().predicates_of(def_id);
+ for f in &variant.fields {
+ tcx.ensure().generics_of(f.did);
+ tcx.ensure().type_of(f.did);
+ tcx.ensure().predicates_of(f.did);
}
// Convert the ctor, if any. This also registers the variant as
// an item.
- if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
- convert_variant_ctor(tcx, ctor_hir_id);
+ if let Some(ctor_def_id) = variant.ctor_def_id() {
+ convert_variant_ctor(tcx, ctor_def_id.expect_local());
}
}
}
@@ -806,7 +802,6 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId, variants: &[hir::V
fn convert_variant(
tcx: TyCtxt<'_>,
variant_did: Option<LocalDefId>,
- ctor_did: Option<LocalDefId>,
ident: Ident,
discr: ty::VariantDiscr,
def: &hir::VariantData<'_>,
@@ -818,7 +813,6 @@ fn convert_variant(
.fields()
.iter()
.map(|f| {
- let fid = tcx.hir().local_def_id(f.hir_id);
let dup_span = seen_fields.get(&f.ident.normalize_to_macros_2_0()).cloned();
if let Some(prev_span) = dup_span {
tcx.sess.emit_err(errors::FieldAlreadyDeclared {
@@ -830,7 +824,11 @@ fn convert_variant(
seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
}
- ty::FieldDef { did: fid.to_def_id(), name: f.ident.name, vis: tcx.visibility(fid) }
+ ty::FieldDef {
+ did: f.def_id.to_def_id(),
+ name: f.ident.name,
+ vis: tcx.visibility(f.def_id),
+ }
})
.collect();
let recovered = match def {
@@ -840,10 +838,9 @@ fn convert_variant(
ty::VariantDef::new(
ident.name,
variant_did.map(LocalDefId::to_def_id),
- ctor_did.map(LocalDefId::to_def_id),
+ def.ctor().map(|(kind, _, def_id)| (kind, def_id.to_def_id())),
discr,
fields,
- CtorKind::from_hir(def),
adt_kind,
parent_did.to_def_id(),
recovered,
@@ -863,7 +860,7 @@ fn adt_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AdtDef<'tcx> {
bug!();
};
- let repr = ReprOptions::new(tcx, def_id.to_def_id());
+ let repr = tcx.repr_options_of_def(def_id.to_def_id());
let (kind, variants) = match item.kind {
ItemKind::Enum(ref def, _) => {
let mut distance_from_explicit = 0;
@@ -871,13 +868,9 @@ fn adt_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AdtDef<'tcx> {
.variants
.iter()
.map(|v| {
- let variant_did = Some(tcx.hir().local_def_id(v.id));
- let ctor_did =
- v.data.ctor_hir_id().map(|hir_id| tcx.hir().local_def_id(hir_id));
-
let discr = if let Some(ref e) = v.disr_expr {
distance_from_explicit = 0;
- ty::VariantDiscr::Explicit(tcx.hir().local_def_id(e.hir_id).to_def_id())
+ ty::VariantDiscr::Explicit(e.def_id.to_def_id())
} else {
ty::VariantDiscr::Relative(distance_from_explicit)
};
@@ -885,8 +878,7 @@ fn adt_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AdtDef<'tcx> {
convert_variant(
tcx,
- variant_did,
- ctor_did,
+ Some(v.def_id),
v.ident,
discr,
&v.data,
@@ -898,41 +890,23 @@ fn adt_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AdtDef<'tcx> {
(AdtKind::Enum, variants)
}
- ItemKind::Struct(ref def, _) => {
- let variant_did = None::<LocalDefId>;
- let ctor_did = def.ctor_hir_id().map(|hir_id| tcx.hir().local_def_id(hir_id));
-
- let variants = std::iter::once(convert_variant(
- tcx,
- variant_did,
- ctor_did,
- item.ident,
- ty::VariantDiscr::Relative(0),
- def,
- AdtKind::Struct,
- def_id,
- ))
- .collect();
-
- (AdtKind::Struct, variants)
- }
- ItemKind::Union(ref def, _) => {
- let variant_did = None;
- let ctor_did = def.ctor_hir_id().map(|hir_id| tcx.hir().local_def_id(hir_id));
-
+ ItemKind::Struct(ref def, _) | ItemKind::Union(ref def, _) => {
+ let adt_kind = match item.kind {
+ ItemKind::Struct(..) => AdtKind::Struct,
+ _ => AdtKind::Union,
+ };
let variants = std::iter::once(convert_variant(
tcx,
- variant_did,
- ctor_did,
+ None,
item.ident,
ty::VariantDiscr::Relative(0),
def,
- AdtKind::Union,
+ adt_kind,
def_id,
))
.collect();
- (AdtKind::Union, variants)
+ (adt_kind, variants)
}
_ => bug!(),
};
@@ -1181,10 +1155,9 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
compute_sig_of_foreign_fn_decl(tcx, def_id.to_def_id(), fn_decl, abi)
}
- Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor_hir_id().is_some() => {
+ Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => {
let ty = tcx.type_of(tcx.hir().get_parent_item(hir_id));
- let inputs =
- data.fields().iter().map(|f| tcx.type_of(tcx.hir().local_def_id(f.hir_id)));
+ let inputs = data.fields().iter().map(|f| tcx.type_of(f.def_id));
ty::Binder::dummy(tcx.mk_fn_sig(
inputs,
ty,
@@ -1394,12 +1367,14 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate
"predicates_defined_on: inferred_outlives_of({:?}) = {:?}",
def_id, inferred_outlives,
);
+ let inferred_outlives_iter =
+ inferred_outlives.iter().map(|(clause, span)| ((*clause).to_predicate(tcx), *span));
if result.predicates.is_empty() {
- result.predicates = inferred_outlives;
+ result.predicates = tcx.arena.alloc_from_iter(inferred_outlives_iter);
} else {
- result.predicates = tcx
- .arena
- .alloc_from_iter(result.predicates.iter().chain(inferred_outlives).copied());
+ result.predicates = tcx.arena.alloc_from_iter(
+ result.predicates.into_iter().copied().chain(inferred_outlives_iter),
+ );
}
}
@@ -1840,7 +1815,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
);
} else if attr.has_name(sym::linkage) {
if let Some(val) = attr.value_str() {
- codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, did, val.as_str()));
+ let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
+ if tcx.is_foreign_item(did) {
+ codegen_fn_attrs.import_linkage = linkage;
+ } else {
+ codegen_fn_attrs.linkage = linkage;
+ }
}
} else if attr.has_name(sym::link_section) {
if let Some(val) = attr.value_str() {
@@ -2099,17 +2079,25 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
}
}
+ if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
+ codegen_fn_attrs.inline = InlineAttr::Never;
+ }
+
// Weak lang items have the same semantics as "std internal" symbols in the
// sense that they're preserved through all our LTO passes and only
// strippable by the linker.
//
// Additionally weak lang items have predetermined symbol names.
- if tcx.is_weak_lang_item(did.to_def_id()) {
+ if WEAK_LANG_ITEMS.iter().any(|&l| tcx.lang_items().get(l) == Some(did.to_def_id())) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
}
- if let Some(name) = weak_lang_items::link_name(attrs) {
- codegen_fn_attrs.export_name = Some(name);
- codegen_fn_attrs.link_name = Some(name);
+ if let Some((name, _)) = lang_items::extract(attrs)
+ && let Some(lang_item) = LangItem::from_name(name)
+ && let Some(link_name) = lang_item.link_name()
+ {
+ codegen_fn_attrs.export_name = Some(link_name);
+ codegen_fn_attrs.link_name = Some(link_name);
}
check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span);
@@ -2170,7 +2158,7 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
}
fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
- use rustc_ast::{Lit, LitIntType, LitKind};
+ use rustc_ast::{LitIntType, LitKind, MetaItemLit};
if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" {
feature_err(
&tcx.sess.parse_sess,
@@ -2181,9 +2169,9 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
.emit();
}
let meta_item_list = attr.meta_item_list();
- let meta_item_list: Option<&[ast::NestedMetaItem]> = meta_item_list.as_ref().map(Vec::as_ref);
+ let meta_item_list = meta_item_list.as_deref();
let sole_meta_list = match meta_item_list {
- Some([item]) => item.literal(),
+ Some([item]) => item.lit(),
Some(_) => {
tcx.sess
.struct_span_err(attr.span, "incorrect number of arguments to `#[link_ordinal]`")
@@ -2193,7 +2181,9 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
}
_ => None,
};
- if let Some(Lit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) = sole_meta_list {
+ if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) =
+ sole_meta_list
+ {
// According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header,
// the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
// in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information
@@ -2261,3 +2251,13 @@ fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span:
}
}
}
+
+fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
+ match tcx.hir().get_if_local(def_id) {
+ Some(Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. })) => {
+ matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias)
+ }
+ Some(_) => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id),
+ _ => bug!("tried getting opaque_ty_origin for non-local def-id {:?}", def_id),
+ }
+}
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index c7777a946..639f81f20 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -51,7 +51,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
None
} else if tcx.lazy_normalization() {
- if let Some(param_id) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) {
+ if let Some(param_id) = tcx.hir().opt_const_param_default_param_def_id(hir_id) {
// If the def_id we are calling generics_of on is an anon ct default i.e:
//
// struct Foo<const N: usize = { .. }>;
@@ -77,8 +77,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
// This has some implications for how we get the predicates available to the anon const
// see `explicit_predicates_of` for more information on this
let generics = tcx.generics_of(parent_def_id.to_def_id());
- let param_def = tcx.hir().local_def_id(param_id).to_def_id();
- let param_def_idx = generics.param_def_id_to_index[&param_def];
+ let param_def_idx = generics.param_def_id_to_index[&param_id.to_def_id()];
// In the above example this would be .params[..N#0]
let params = generics.params[..param_def_idx as usize].to_owned();
let param_def_id_to_index =
@@ -241,7 +240,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
name: param.name.ident().name,
index: own_start + i as u32,
- def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
+ def_id: param.def_id.to_def_id(),
pure_wrt_drop: param.pure_wrt_drop,
kind: ty::GenericParamDefKind::Lifetime,
}));
@@ -286,7 +285,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
Some(ty::GenericParamDef {
index: next_index(),
name: param.name.ident().name,
- def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
+ def_id: param.def_id.to_def_id(),
pure_wrt_drop: param.pure_wrt_drop,
kind,
})
@@ -303,7 +302,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
Some(ty::GenericParamDef {
index: next_index(),
name: param.name.ident().name,
- def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
+ def_id: param.def_id.to_def_id(),
pure_wrt_drop: param.pure_wrt_drop,
kind: ty::GenericParamDefKind::Const { has_default: default.is_some() },
})
@@ -399,7 +398,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
Some(rl::Region::Static | rl::Region::EarlyBound(..)) => {}
Some(rl::Region::LateBound(debruijn, _, _)) if debruijn < self.outer_index => {}
Some(rl::Region::LateBound(..) | rl::Region::Free(..)) | None => {
- self.has_late_bound_regions = Some(lt.span);
+ self.has_late_bound_regions = Some(lt.ident.span);
}
}
}
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 0d34a8bfe..0542e2c8f 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -35,9 +35,11 @@ fn associated_type_bounds<'tcx>(
let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| {
match pred.kind().skip_binder() {
- ty::PredicateKind::Trait(tr) => tr.self_ty() == item_ty,
- ty::PredicateKind::Projection(proj) => proj.projection_ty.self_ty() == item_ty,
- ty::PredicateKind::TypeOutlives(outlives) => outlives.0 == item_ty,
+ ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => tr.self_ty() == item_ty,
+ ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => {
+ proj.projection_ty.self_ty() == item_ty
+ }
+ ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => outlives.0 == item_ty,
_ => false,
}
});
diff --git a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
index 3f263a6de..e4fe3e90e 100644
--- a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
+++ b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
@@ -15,19 +15,18 @@ use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node};
use rustc_middle::bug;
-use rustc_middle::hir::map::Map;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_lifetime::*;
-use rustc_middle::ty::{self, DefIdTree, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, TyCtxt, TypeSuperVisitable, TypeVisitor};
use rustc_span::def_id::DefId;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use std::fmt;
trait RegionExt {
- fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region);
+ fn early(param: &GenericParam<'_>) -> (LocalDefId, Region);
- fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region);
+ fn late(index: u32, param: &GenericParam<'_>) -> (LocalDefId, Region);
fn id(&self) -> Option<DefId>;
@@ -35,20 +34,18 @@ trait RegionExt {
}
impl RegionExt for Region {
- fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) {
- let def_id = hir_map.local_def_id(param.hir_id);
- debug!("Region::early: def_id={:?}", def_id);
- (def_id, Region::EarlyBound(def_id.to_def_id()))
+ fn early(param: &GenericParam<'_>) -> (LocalDefId, Region) {
+ debug!("Region::early: def_id={:?}", param.def_id);
+ (param.def_id, Region::EarlyBound(param.def_id.to_def_id()))
}
- fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) {
+ fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, Region) {
let depth = ty::INNERMOST;
- let def_id = hir_map.local_def_id(param.hir_id);
debug!(
"Region::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
- idx, param, depth, def_id,
+ idx, param, depth, param.def_id,
);
- (def_id, Region::LateBound(depth, idx, def_id.to_def_id()))
+ (param.def_id, Region::LateBound(depth, idx, param.def_id.to_def_id()))
}
fn id(&self) -> Option<DefId> {
@@ -94,11 +91,6 @@ struct LifetimeContext<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
map: &'a mut NamedRegionMap,
scope: ScopeRef<'a>,
-
- /// Indicates that we only care about the definition of a trait. This should
- /// be false if the `Item` we are resolving lifetimes for is not a trait or
- /// we eventually need lifetimes resolve for trait items.
- trait_definition_only: bool,
}
#[derive(Debug)]
@@ -166,7 +158,9 @@ enum Scope<'a> {
s: ScopeRef<'a>,
},
- Root,
+ Root {
+ opt_parent_item: Option<LocalDefId>,
+ },
}
#[derive(Copy, Clone, Debug)]
@@ -214,95 +208,58 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
.field("s", &"..")
.finish(),
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
- Scope::Root => f.debug_struct("Root").finish(),
+ Scope::Root { opt_parent_item } => {
+ f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
+ }
}
}
}
type ScopeRef<'a> = &'a Scope<'a>;
-const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root;
-
pub(crate) fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers {
- resolve_lifetimes_trait_definition,
resolve_lifetimes,
- named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id),
+ named_region_map: |tcx, id| tcx.resolve_lifetimes(id).defs.get(&id),
is_late_bound_map,
object_lifetime_default,
- late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id),
+ late_bound_vars_map: |tcx, id| tcx.resolve_lifetimes(id).late_bound_vars.get(&id),
..*providers
};
}
-/// Like `resolve_lifetimes`, but does not resolve lifetimes for trait items.
-/// Also does not generate any diagnostics.
-///
-/// This is ultimately a subset of the `resolve_lifetimes` work. It effectively
-/// resolves lifetimes only within the trait "header" -- that is, the trait
-/// and supertrait list. In contrast, `resolve_lifetimes` resolves all the
-/// lifetimes within the trait and its items. There is room to refactor this,
-/// for example to resolve lifetimes for each trait item in separate queries,
-/// but it's convenient to do the entire trait at once because the lifetimes
-/// from the trait definition are in scope within the trait items as well.
-///
-/// The reason for this separate call is to resolve what would otherwise
-/// be a cycle. Consider this example:
-///
-/// ```ignore UNSOLVED (maybe @jackh726 knows what lifetime parameter to give Sub)
-/// trait Base<'a> {
-/// type BaseItem;
-/// }
-/// trait Sub<'b>: for<'a> Base<'a> {
-/// type SubItem: Sub<BaseItem = &'b u32>;
-/// }
-/// ```
-///
-/// When we resolve `Sub` and all its items, we also have to resolve `Sub<BaseItem = &'b u32>`.
-/// To figure out the index of `'b`, we have to know about the supertraits
-/// of `Sub` so that we can determine that the `for<'a>` will be in scope.
-/// (This is because we -- currently at least -- flatten all the late-bound
-/// lifetimes into a single binder.) This requires us to resolve the
-/// *trait definition* of `Sub`; basically just enough lifetime information
-/// to look at the supertraits.
-#[instrument(level = "debug", skip(tcx))]
-fn resolve_lifetimes_trait_definition(
- tcx: TyCtxt<'_>,
- local_def_id: LocalDefId,
-) -> ResolveLifetimes {
- convert_named_region_map(do_resolve(tcx, local_def_id, true))
-}
-
/// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
/// You should not read the result of this query directly, but rather use
/// `named_region_map`, `is_late_bound_map`, etc.
#[instrument(level = "debug", skip(tcx))]
-fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes {
- convert_named_region_map(do_resolve(tcx, local_def_id, false))
-}
-
-fn do_resolve(
- tcx: TyCtxt<'_>,
- local_def_id: LocalDefId,
- trait_definition_only: bool,
-) -> NamedRegionMap {
- let item = tcx.hir().expect_item(local_def_id);
+fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveLifetimes {
let mut named_region_map =
NamedRegionMap { defs: Default::default(), late_bound_vars: Default::default() };
let mut visitor = LifetimeContext {
tcx,
map: &mut named_region_map,
- scope: ROOT_SCOPE,
- trait_definition_only,
+ scope: &Scope::Root { opt_parent_item: None },
};
- visitor.visit_item(item);
-
- named_region_map
-}
+ match tcx.hir().owner(local_def_id) {
+ hir::OwnerNode::Item(item) => visitor.visit_item(item),
+ hir::OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
+ hir::OwnerNode::TraitItem(item) => {
+ let scope =
+ Scope::Root { opt_parent_item: Some(tcx.local_parent(item.owner_id.def_id)) };
+ visitor.scope = &scope;
+ visitor.visit_trait_item(item)
+ }
+ hir::OwnerNode::ImplItem(item) => {
+ let scope =
+ Scope::Root { opt_parent_item: Some(tcx.local_parent(item.owner_id.def_id)) };
+ visitor.scope = &scope;
+ visitor.visit_impl_item(item)
+ }
+ hir::OwnerNode::Crate(_) => {}
+ }
-fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetimes {
let mut rl = ResolveLifetimes::default();
for (hir_id, v) in named_region_map.defs {
@@ -319,53 +276,6 @@ fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetime
rl
}
-/// Given `any` owner (structs, traits, trait methods, etc.), does lifetime resolution.
-/// There are two important things this does.
-/// First, we have to resolve lifetimes for
-/// the entire *`Item`* that contains this owner, because that's the largest "scope"
-/// where we can have relevant lifetimes.
-/// Second, if we are asking for lifetimes in a trait *definition*, we use `resolve_lifetimes_trait_definition`
-/// instead of `resolve_lifetimes`, which does not descend into the trait items and does not emit diagnostics.
-/// This allows us to avoid cycles. Importantly, if we ask for lifetimes for lifetimes that have an owner
-/// other than the trait itself (like the trait methods or associated types), then we just use the regular
-/// `resolve_lifetimes`.
-fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: hir::OwnerId) -> &'tcx ResolveLifetimes {
- let item_id = item_for(tcx, def_id.def_id);
- let local_def_id = item_id.owner_id.def_id;
- if item_id.owner_id == def_id {
- let item = tcx.hir().item(item_id);
- match item.kind {
- hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_trait_definition(local_def_id),
- _ => tcx.resolve_lifetimes(local_def_id),
- }
- } else {
- tcx.resolve_lifetimes(local_def_id)
- }
-}
-
-/// Finds the `Item` that contains the given `LocalDefId`
-fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> hir::ItemId {
- match tcx.hir().find_by_def_id(local_def_id) {
- Some(Node::Item(item)) => {
- return item.item_id();
- }
- _ => {}
- }
- let item = {
- let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id);
- let mut parent_iter = tcx.hir().parent_iter(hir_id);
- loop {
- let node = parent_iter.next().map(|n| n.1);
- match node {
- Some(hir::Node::Item(item)) => break item.item_id(),
- Some(hir::Node::Crate(_)) | None => bug!("Called `item_for` on an Item."),
- _ => {}
- }
- }
- };
- item
-}
-
fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind {
match region {
Region::LateBound(_, _, def_id) => {
@@ -383,7 +293,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let mut supertrait_lifetimes = vec![];
loop {
match scope {
- Scope::Body { .. } | Scope::Root => {
+ Scope::Body { .. } | Scope::Root { .. } => {
break (vec![], BinderScopeType::Normal);
}
@@ -414,21 +324,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
}
impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
- type NestedFilter = nested_filter::All;
+ type NestedFilter = nested_filter::OnlyBodies;
fn nested_visit_map(&mut self) -> Self::Map {
self.tcx.hir()
}
- // We want to nest trait/impl items in their parent, but nothing else.
- fn visit_nested_item(&mut self, _: hir::ItemId) {}
-
- fn visit_trait_item_ref(&mut self, ii: &'tcx hir::TraitItemRef) {
- if !self.trait_definition_only {
- intravisit::walk_trait_item_ref(self, ii)
- }
- }
-
fn visit_nested_body(&mut self, body: hir::BodyId) {
let body = self.tcx.hir().body(body);
self.with(Scope::Body { id: body.id(), s: self.scope }, |this| {
@@ -491,7 +392,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
.filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param);
+ let pair = Region::late(late_bound_idx as u32, param);
let r = late_region_as_bound_region(self.tcx, &pair.1);
(pair, r)
})
@@ -548,7 +449,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
intravisit::walk_item(this, item)
});
}
- hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => {
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ origin: hir::OpaqueTyOrigin::TyAlias, ..
+ }) => {
// Opaque types are visited when we visit the
// `TyKind::OpaqueDef`, so that they have the lifetimes from
// their parent opaque_ty in scope.
@@ -557,34 +460,53 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// their owner, we can keep going until we find the Item that owns that. We then
// conservatively add all resolved lifetimes. Otherwise we run into problems in
// cases like `type Foo<'a> = impl Bar<As = impl Baz + 'a>`.
- for (_hir_id, node) in self.tcx.hir().parent_iter(item.owner_id.into()) {
- match node {
- hir::Node::Item(parent_item) => {
- let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes(
- item_for(self.tcx, parent_item.owner_id.def_id).owner_id.def_id,
- );
- // We need to add *all* deps, since opaque tys may want them from *us*
- for (&owner, defs) in resolved_lifetimes.defs.iter() {
- defs.iter().for_each(|(&local_id, region)| {
- self.map.defs.insert(hir::HirId { owner, local_id }, *region);
- });
- }
- for (&owner, late_bound_vars) in
- resolved_lifetimes.late_bound_vars.iter()
- {
- late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| {
- self.record_late_bound_vars(
- hir::HirId { owner, local_id },
- late_bound_vars.clone(),
- );
- });
- }
- break;
+ let parent_item = self.tcx.hir().get_parent_item(item.hir_id());
+ let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes(parent_item);
+ // We need to add *all* deps, since opaque tys may want them from *us*
+ for (&owner, defs) in resolved_lifetimes.defs.iter() {
+ defs.iter().for_each(|(&local_id, region)| {
+ self.map.defs.insert(hir::HirId { owner, local_id }, *region);
+ });
+ }
+ for (&owner, late_bound_vars) in resolved_lifetimes.late_bound_vars.iter() {
+ late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| {
+ self.record_late_bound_vars(
+ hir::HirId { owner, local_id },
+ late_bound_vars.clone(),
+ );
+ });
+ }
+ }
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ origin: hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_),
+ generics,
+ ..
+ }) => {
+ // We want to start our early-bound indices at the end of the parent scope,
+ // not including any parent `impl Trait`s.
+ let mut lifetimes = FxIndexMap::default();
+ debug!(?generics.params);
+ for param in generics.params {
+ match param.kind {
+ GenericParamKind::Lifetime { .. } => {
+ let (def_id, reg) = Region::early(&param);
+ lifetimes.insert(def_id, reg);
}
- hir::Node::Crate(_) => bug!("No Item about an OpaqueTy"),
- _ => {}
+ GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {}
}
}
+
+ let scope = Scope::Binder {
+ hir_id: item.hir_id(),
+ lifetimes,
+ s: self.scope,
+ scope_type: BinderScopeType::Normal,
+ where_bound_origin: None,
+ };
+ self.with(scope, |this| {
+ let scope = Scope::TraitRefBoundary { s: this.scope };
+ this.with(scope, |this| intravisit::walk_item(this, item))
+ });
}
hir::ItemKind::TyAlias(_, ref generics)
| hir::ItemKind::Enum(_, ref generics)
@@ -598,9 +520,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
.params
.iter()
.filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => {
- Some(Region::early(self.tcx.hir(), param))
- }
+ GenericParamKind::Lifetime { .. } => Some(Region::early(param)),
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
})
.collect();
@@ -609,7 +529,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
hir_id: item.hir_id(),
lifetimes,
scope_type: BinderScopeType::Normal,
- s: ROOT_SCOPE,
+ s: self.scope,
where_bound_origin: None,
};
self.with(scope, |this| {
@@ -648,7 +568,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
.filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param);
+ let pair = Region::late(late_bound_idx as u32, param);
let r = late_region_as_bound_region(self.tcx, &pair.1);
(pair, r)
})
@@ -675,7 +595,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
this.visit_poly_trait_ref(bound);
}
});
- match lifetime.name {
+ match lifetime.res {
LifetimeName::ImplicitObjectLifetimeDefault => {
// If the user does not write *anything*, we
// use the object lifetime defaulting
@@ -712,7 +632,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// ^ ^ this gets resolved in the scope of
// the opaque_ty generics
let opaque_ty = self.tcx.hir().item(item_id);
- let (generics, bounds) = match opaque_ty.kind {
+ match opaque_ty.kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias,
..
@@ -733,10 +653,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..),
- ref generics,
- bounds,
..
- }) => (generics, bounds),
+ }) => {}
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
};
@@ -766,65 +684,28 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// Ensure that the parent of the def is an item, not HRTB
let parent_id = self.tcx.hir().get_parent_node(hir_id);
if !parent_id.is_owner() {
- if !self.trait_definition_only {
- struct_span_err!(
- self.tcx.sess,
- lifetime.span,
- E0657,
- "`impl Trait` can only capture lifetimes \
- bound at the fn or impl level"
- )
- .emit();
- }
+ struct_span_err!(
+ self.tcx.sess,
+ lifetime.ident.span,
+ E0657,
+ "`impl Trait` can only capture lifetimes bound at the fn or impl level"
+ )
+ .emit();
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
}
if let hir::Node::Item(hir::Item {
kind: hir::ItemKind::OpaqueTy { .. }, ..
}) = self.tcx.hir().get(parent_id)
{
- if !self.trait_definition_only {
- let mut err = self.tcx.sess.struct_span_err(
- lifetime.span,
- "higher kinded lifetime bounds on nested opaque types are not supported yet",
- );
- err.span_note(self.tcx.def_span(def_id), "lifetime declared here");
- err.emit();
- }
+ let mut err = self.tcx.sess.struct_span_err(
+ lifetime.ident.span,
+ "higher kinded lifetime bounds on nested opaque types are not supported yet",
+ );
+ err.span_note(self.tcx.def_span(def_id), "lifetime declared here");
+ err.emit();
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
}
}
-
- // We want to start our early-bound indices at the end of the parent scope,
- // not including any parent `impl Trait`s.
- let mut lifetimes = FxIndexMap::default();
- debug!(?generics.params);
- for param in generics.params {
- match param.kind {
- GenericParamKind::Lifetime { .. } => {
- let (def_id, reg) = Region::early(self.tcx.hir(), &param);
- lifetimes.insert(def_id, reg);
- }
- GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {}
- }
- }
- self.record_late_bound_vars(ty.hir_id, vec![]);
-
- let scope = Scope::Binder {
- hir_id: ty.hir_id,
- lifetimes,
- s: self.scope,
- scope_type: BinderScopeType::Normal,
- where_bound_origin: None,
- };
- self.with(scope, |this| {
- let scope = Scope::TraitRefBoundary { s: this.scope };
- this.with(scope, |this| {
- this.visit_generics(generics);
- for bound in bounds {
- this.visit_param_bound(bound);
- }
- })
- });
}
_ => intravisit::walk_ty(self, ty),
}
@@ -845,9 +726,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
.params
.iter()
.filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => {
- Some(Region::early(self.tcx.hir(), param))
- }
+ GenericParamKind::Lifetime { .. } => Some(Region::early(param)),
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
})
.collect();
@@ -893,9 +772,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
.params
.iter()
.filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => {
- Some(Region::early(self.tcx.hir(), param))
- }
+ GenericParamKind::Lifetime { .. } => Some(Region::early(param)),
GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => None,
})
.collect();
@@ -925,9 +802,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
#[instrument(level = "debug", skip(self))]
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
- match lifetime_ref.name {
+ match lifetime_ref.res {
hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static),
- hir::LifetimeName::Param(param_def_id, _) => {
+ hir::LifetimeName::Param(param_def_id) => {
self.resolve_lifetime_ref(param_def_id, lifetime_ref)
}
// If we've already reported an error, just ignore `lifetime_ref`.
@@ -937,7 +814,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
}
- fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
+ fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
for (i, segment) in path.segments.iter().enumerate() {
let depth = path.segments.len() - i - 1;
if let Some(ref args) = segment.args {
@@ -1000,7 +877,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
})
.enumerate()
.map(|(late_bound_idx, param)| {
- Region::late(late_bound_idx as u32, this.tcx.hir(), param)
+ Region::late(late_bound_idx as u32, param)
})
.collect();
let binders: Vec<_> =
@@ -1035,27 +912,27 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
this.visit_lifetime(lifetime);
walk_list!(this, visit_param_bound, bounds);
- if lifetime.name != hir::LifetimeName::Static {
+ if lifetime.res != hir::LifetimeName::Static {
for bound in bounds {
let hir::GenericBound::Outlives(ref lt) = bound else {
continue;
};
- if lt.name != hir::LifetimeName::Static {
+ if lt.res != hir::LifetimeName::Static {
continue;
}
this.insert_lifetime(lt, Region::Static);
this.tcx
.sess
.struct_span_warn(
- lifetime.span,
+ lifetime.ident.span,
&format!(
"unnecessary lifetime parameter `{}`",
- lifetime.name.ident(),
+ lifetime.ident,
),
)
.help(&format!(
"you can use the `'static` lifetime directly, in place of `{}`",
- lifetime.name.ident(),
+ lifetime.ident,
))
.emit();
}
@@ -1113,8 +990,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
.filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair =
- Region::late(initial_bound_vars + late_bound_idx as u32, self.tcx.hir(), param);
+ let pair = Region::late(initial_bound_vars + late_bound_idx as u32, param);
let r = late_region_as_bound_region(self.tcx, &pair.1);
lifetimes.insert(pair.0, pair.1);
r
@@ -1167,7 +1043,7 @@ fn object_lifetime_default<'tcx>(tcx: TyCtxt<'tcx>, param_def_id: DefId) -> Obje
for bound in bound.bounds {
if let hir::GenericBound::Outlives(ref lifetime) = *bound {
- set.insert(lifetime.name.normalize_to_macros_2_0());
+ set.insert(lifetime.res);
}
}
}
@@ -1175,7 +1051,7 @@ fn object_lifetime_default<'tcx>(tcx: TyCtxt<'tcx>, param_def_id: DefId) -> Obje
match set {
Set1::Empty => ObjectLifetimeDefault::Empty,
Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static,
- Set1::One(hir::LifetimeName::Param(param_def_id, _)) => {
+ Set1::One(hir::LifetimeName::Param(param_def_id)) => {
ObjectLifetimeDefault::Param(param_def_id.to_def_id())
}
_ => ObjectLifetimeDefault::Ambiguous,
@@ -1193,12 +1069,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
{
let LifetimeContext { tcx, map, .. } = self;
- let mut this = LifetimeContext {
- tcx: *tcx,
- map,
- scope: &wrap_scope,
- trait_definition_only: self.trait_definition_only,
- };
+ let mut this = LifetimeContext { tcx: *tcx, map, scope: &wrap_scope };
let span = debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
{
let _enter = span.enter();
@@ -1250,9 +1121,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
if self.tcx.is_late_bound(param.hir_id) {
let late_bound_idx = named_late_bound_vars;
named_late_bound_vars += 1;
- Some(Region::late(late_bound_idx, self.tcx.hir(), param))
+ Some(Region::late(late_bound_idx, param))
} else {
- Some(Region::early(self.tcx.hir(), param))
+ Some(Region::early(param))
}
}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
@@ -1268,7 +1139,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
})
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param);
+ let pair = Region::late(late_bound_idx as u32, param);
late_region_as_bound_region(self.tcx, &pair.1)
})
.collect();
@@ -1303,7 +1174,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
scope = s;
}
- Scope::Root => {
+ 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.contains_key(&region_def_id.to_def_id())
+ {
+ break Some(Region::EarlyBound(region_def_id.to_def_id()));
+ }
break None;
}
@@ -1318,42 +1195,52 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
// Fresh lifetimes in APIT used to be allowed in async fns and forbidden in
// regular fns.
if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
- && let hir::LifetimeName::Param(_, hir::ParamName::Fresh) = lifetime_ref.name
+ && 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(param) = generics.params.iter().find(|p| p.def_id == param_id)
+ && param.is_elided_lifetime()
&& let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id)
&& !self.tcx.features().anonymous_lifetime_in_impl_trait
{
let mut diag = rustc_session::parse::feature_err(
&self.tcx.sess.parse_sess,
sym::anonymous_lifetime_in_impl_trait,
- lifetime_ref.span,
+ lifetime_ref.ident.span,
"anonymous lifetimes in `impl Trait` are unstable",
);
- match self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id) {
- Some(generics) => {
-
- let new_param_sugg_tuple;
-
- new_param_sugg_tuple = match generics.span_for_param_suggestion() {
- Some(_) => {
- Some((self.tcx.sess.source_map().span_through_char(generics.span, '<').shrink_to_hi(), "'a, ".to_owned()))
- },
- None => Some((generics.span, "<'a>".to_owned()))
- };
-
- let mut multi_sugg_vec = vec![(lifetime_ref.span.shrink_to_hi(), "'a ".to_owned())];
-
- if let Some(new_tuple) = new_param_sugg_tuple{
- multi_sugg_vec.push(new_tuple);
- }
-
- diag.span_label(lifetime_ref.span, "expected named lifetime parameter");
- diag.multipart_suggestion("consider introducing a named lifetime parameter",
- multi_sugg_vec,
- rustc_errors::Applicability::MaybeIncorrect);
-
- },
- None => { }
+ 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 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()),
+ };
+ let suggestions = vec![
+ lifetime_sugg,
+ new_param_sugg,
+ ];
+
+ diag.span_label(
+ lifetime_ref.ident.span,
+ "expected named lifetime parameter",
+ );
+ diag.multipart_suggestion(
+ "consider introducing a named lifetime parameter",
+ suggestions,
+ rustc_errors::Applicability::MaybeIncorrect,
+ );
}
diag.emit();
@@ -1377,11 +1264,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
} else if let Some(body_id) = outermost_body {
let fn_id = self.tcx.hir().body_owner(body_id);
match self.tcx.hir().get(fn_id) {
- Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. })
- | Node::TraitItem(&hir::TraitItem {
+ Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
+ | Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(..), ..
})
- | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => {
+ | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. })
+ | Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
let scope = self.tcx.hir().local_def_id(fn_id);
def = Region::Free(scope.to_def_id(), def.id().unwrap());
}
@@ -1409,14 +1297,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), ..
} => {
let mut err = self.tcx.sess.struct_span_err(
- lifetime_ref.span,
+ lifetime_ref.ident.span,
"`impl Trait` can only mention lifetimes bound at the fn or impl level",
);
err.span_note(self.tcx.def_span(region_def_id), "lifetime declared here");
err.emit();
return;
}
- Scope::Root => break,
+ Scope::Root { .. } => break,
Scope::Binder { s, .. }
| Scope::Body { s, .. }
| Scope::Elision { s, .. }
@@ -1429,7 +1317,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
self.tcx.sess.delay_span_bug(
- lifetime_ref.span,
+ lifetime_ref.ident.span,
&format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,),
);
}
@@ -1494,7 +1382,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let mut scope = self.scope;
loop {
match *scope {
- Scope::Root => break false,
+ Scope::Root { .. } => break false,
Scope::Body { .. } => break true,
@@ -1680,7 +1568,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| {
let bound_predicate = pred.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(data) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
// The order here needs to match what we would get from `subst_supertrait`
let pred_bound_vars = bound_predicate.bound_vars();
let mut all_bound_vars = bound_vars.clone();
@@ -1731,7 +1619,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
scope = s;
}
- Scope::Root | Scope::Elision { .. } => break Region::Static,
+ Scope::Root { .. } | Scope::Elision { .. } => break Region::Static,
Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return,
@@ -1747,10 +1635,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
#[instrument(level = "debug", skip(self))]
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
- debug!(
- node = ?self.tcx.hir().node_to_string(lifetime_ref.hir_id),
- span = ?self.tcx.sess.source_map().span_to_diagnostic_string(lifetime_ref.span)
- );
+ debug!(span = ?lifetime_ref.ident.span);
self.map.defs.insert(lifetime_ref.hir_id, def);
}
@@ -1780,7 +1665,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
let mut late_bound = FxIndexSet::default();
- let mut constrained_by_input = ConstrainedCollector::default();
+ let mut constrained_by_input = ConstrainedCollector { regions: Default::default(), tcx };
for arg_ty in decl.inputs {
constrained_by_input.visit_ty(arg_ty);
}
@@ -1833,12 +1718,65 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
debug!(?late_bound);
return Some(tcx.arena.alloc(late_bound));
- #[derive(Default)]
- struct ConstrainedCollector {
+ /// Visits a `ty::Ty` collecting information about what generic parameters are constrained.
+ ///
+ /// The visitor does not operate on `hir::Ty` so that it can be called on the rhs of a `type Alias<...> = ...;`
+ /// which may live in a separate crate so there would not be any hir available. Instead we use the `type_of`
+ /// query to obtain a `ty::Ty` which will be present even in cross crate scenarios. It also naturally
+ /// handles cycle detection as we go through the query system.
+ ///
+ /// This is necessary in the first place for the following case:
+ /// ```
+ /// type Alias<'a, T> = <T as Trait<'a>>::Assoc;
+ /// fn foo<'a>(_: Alias<'a, ()>) -> Alias<'a, ()> { ... }
+ /// ```
+ ///
+ /// If we conservatively considered `'a` unconstrained then we could break users who had written code before
+ /// we started correctly handling aliases. If we considered `'a` constrained then it would become late bound
+ /// causing an error during astconv as the `'a` is not constrained by the input type `<() as Trait<'a>>::Assoc`
+ /// but appears in the output type `<() as Trait<'a>>::Assoc`.
+ ///
+ /// We must therefore "look into" the `Alias` to see whether we should consider `'a` constrained or not.
+ ///
+ /// See #100508 #85533 #47511 for additional context
+ struct ConstrainedCollectorPostAstConv {
+ arg_is_constrained: Box<[bool]>,
+ }
+
+ use std::ops::ControlFlow;
+ use ty::Ty;
+ impl<'tcx> TypeVisitor<'tcx> for ConstrainedCollectorPostAstConv {
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
+ match t.kind() {
+ ty::Param(param_ty) => {
+ self.arg_is_constrained[param_ty.index as usize] = true;
+ }
+ ty::Projection(_) => return ControlFlow::Continue(()),
+ _ => (),
+ }
+ t.super_visit_with(self)
+ }
+
+ fn visit_const(&mut self, _: ty::Const<'tcx>) -> ControlFlow<!> {
+ ControlFlow::Continue(())
+ }
+
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<!> {
+ debug!("r={:?}", r.kind());
+ if let ty::RegionKind::ReEarlyBound(region) = r.kind() {
+ self.arg_is_constrained[region.index as usize] = true;
+ }
+
+ ControlFlow::Continue(())
+ }
+ }
+
+ struct ConstrainedCollector<'tcx> {
+ tcx: TyCtxt<'tcx>,
regions: FxHashSet<LocalDefId>,
}
- impl<'v> Visitor<'v> for ConstrainedCollector {
+ impl<'v> Visitor<'v> for ConstrainedCollector<'_> {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
match ty.kind {
hir::TyKind::Path(
@@ -1849,6 +1787,47 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
// (defined above)
}
+ hir::TyKind::Path(hir::QPath::Resolved(
+ None,
+ hir::Path { res: Res::Def(DefKind::TyAlias, alias_def), segments, span },
+ )) => {
+ // See comments on `ConstrainedCollectorPostAstConv` for why this arm does not just consider
+ // substs to be unconstrained.
+ let generics = self.tcx.generics_of(alias_def);
+ let mut walker = ConstrainedCollectorPostAstConv {
+ arg_is_constrained: vec![false; generics.params.len()].into_boxed_slice(),
+ };
+ walker.visit_ty(self.tcx.type_of(alias_def));
+
+ match segments.last() {
+ Some(hir::PathSegment { args: Some(args), .. }) => {
+ let tcx = self.tcx;
+ for constrained_arg in
+ args.args.iter().enumerate().flat_map(|(n, arg)| {
+ match walker.arg_is_constrained.get(n) {
+ Some(true) => Some(arg),
+ Some(false) => None,
+ None => {
+ tcx.sess.delay_span_bug(
+ *span,
+ format!(
+ "Incorrect generic arg count for alias {:?}",
+ alias_def
+ ),
+ );
+ None
+ }
+ }
+ })
+ {
+ self.visit_generic_arg(constrained_arg);
+ }
+ }
+ Some(_) => (),
+ None => bug!("Path with no segments or self type"),
+ }
+ }
+
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
// consider only the lifetimes on the final
// segment; I am not sure it's even currently
@@ -1867,7 +1846,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
}
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
- if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name {
+ if let hir::LifetimeName::Param(def_id) = lifetime_ref.res {
self.regions.insert(def_id);
}
}
@@ -1880,7 +1859,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
impl<'v> Visitor<'v> for AllCollector {
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
- if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name {
+ if let hir::LifetimeName::Param(def_id) = lifetime_ref.res {
self.regions.insert(def_id);
}
}
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 2e84e1d01..45e241f4e 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -84,60 +84,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
Node::ImplItem(item) => item.generics,
- Node::Item(item) => {
- match item.kind {
- ItemKind::Impl(ref impl_) => {
- if impl_.defaultness.is_default() {
- is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
- }
- &impl_.generics
- }
- ItemKind::Fn(.., ref generics, _)
- | ItemKind::TyAlias(_, ref generics)
- | ItemKind::Enum(_, ref generics)
- | ItemKind::Struct(_, ref generics)
- | ItemKind::Union(_, ref generics) => *generics,
-
- ItemKind::Trait(_, _, ref generics, ..) => {
- is_trait = Some(ty::TraitRef::identity(tcx, def_id));
- *generics
+ Node::Item(item) => match item.kind {
+ ItemKind::Impl(ref impl_) => {
+ if impl_.defaultness.is_default() {
+ is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
}
- ItemKind::TraitAlias(ref generics, _) => {
- is_trait = Some(ty::TraitRef::identity(tcx, def_id));
- *generics
- }
- ItemKind::OpaqueTy(OpaqueTy {
- origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
- ..
- }) => {
- // return-position impl trait
- //
- // We don't inherit predicates from the parent here:
- // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
- // then the return type is `f::<'static, T>::{{opaque}}`.
- //
- // If we inherited the predicates of `f` then we would
- // require that `T: 'static` to show that the return
- // type is well-formed.
- //
- // The only way to have something with this opaque type
- // is from the return type of the containing function,
- // which will ensure that the function's predicates
- // hold.
- return ty::GenericPredicates { parent: None, predicates: &[] };
- }
- ItemKind::OpaqueTy(OpaqueTy {
- ref generics,
- origin: hir::OpaqueTyOrigin::TyAlias,
- ..
- }) => {
- // type-alias impl trait
- generics
- }
-
- _ => NO_GENERICS,
+ &impl_.generics
}
- }
+ ItemKind::Fn(.., ref generics, _)
+ | ItemKind::TyAlias(_, ref generics)
+ | ItemKind::Enum(_, ref generics)
+ | ItemKind::Struct(_, ref generics)
+ | ItemKind::Union(_, ref generics) => *generics,
+
+ ItemKind::Trait(_, _, ref generics, ..) => {
+ is_trait = Some(ty::TraitRef::identity(tcx, def_id));
+ *generics
+ }
+ ItemKind::TraitAlias(ref generics, _) => {
+ is_trait = Some(ty::TraitRef::identity(tcx, def_id));
+ *generics
+ }
+ ItemKind::OpaqueTy(OpaqueTy { ref generics, .. }) => generics,
+ _ => NO_GENERICS,
+ },
Node::ForeignItem(item) => match item.kind {
ForeignItemKind::Static(..) => NO_GENERICS,
@@ -181,6 +151,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
trace!(?predicates);
trace!(?ast_generics);
+ trace!(?generics);
// Collect the predicates that were written inline by the user on each
// type parameter (e.g., `<T: Foo>`).
@@ -199,7 +170,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
&icx,
&mut bounds,
&[],
- Some((param.hir_id, ast_generics.predicates)),
+ Some((param.def_id, ast_generics.predicates)),
param.span,
);
trace!(?bounds);
@@ -258,12 +229,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
predicates.extend(region_pred.bounds.iter().map(|bound| {
let (r2, span) = match bound {
hir::GenericBound::Outlives(lt) => {
- (<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.span)
+ (<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.ident.span)
}
_ => bug!(),
};
- let pred = ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
- ty::OutlivesPredicate(r1, r2),
+ let pred = ty::Binder::dummy(ty::PredicateKind::Clause(
+ ty::Clause::RegionOutlives(ty::OutlivesPredicate(r1, r2)),
))
.to_predicate(icx.tcx);
@@ -299,6 +270,52 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
);
}
+ // Opaque types duplicate some of their generic parameters.
+ // We create bi-directional Outlives predicates between the original
+ // and the duplicated parameter, to ensure that they do not get out of sync.
+ if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node {
+ let opaque_ty_id = tcx.hir().get_parent_node(hir_id);
+ let opaque_ty_node = tcx.hir().get(opaque_ty_id);
+ let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else {
+ bug!("unexpected {opaque_ty_node:?}")
+ };
+ debug!(?lifetimes);
+ for (arg, duplicate) in std::iter::zip(lifetimes, ast_generics.params) {
+ let hir::GenericArg::Lifetime(arg) = arg else { bug!() };
+ let orig_region = <dyn AstConv<'_>>::ast_region_to_region(&icx, &arg, None);
+ if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) {
+ // Only early-bound regions can point to the original generic parameter.
+ continue;
+ }
+
+ let hir::GenericParamKind::Lifetime { .. } = duplicate.kind else { continue };
+ let dup_def = tcx.hir().local_def_id(duplicate.hir_id).to_def_id();
+
+ let Some(dup_index) = generics.param_def_id_to_index(tcx, dup_def) else { bug!() };
+
+ let dup_region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
+ def_id: dup_def,
+ index: dup_index,
+ name: duplicate.name.ident().name,
+ }));
+ predicates.push((
+ ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives(
+ ty::OutlivesPredicate(orig_region, dup_region),
+ )))
+ .to_predicate(icx.tcx),
+ duplicate.span,
+ ));
+ predicates.push((
+ ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives(
+ ty::OutlivesPredicate(dup_region, orig_region),
+ )))
+ .to_predicate(icx.tcx),
+ duplicate.span,
+ ));
+ }
+ debug!(?predicates);
+ }
+
ty::GenericPredicates {
parent: generics.parent,
predicates: tcx.arena.alloc_from_iter(predicates),
@@ -316,10 +333,9 @@ fn const_evaluatable_predicates_of<'tcx>(
impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
- let def_id = self.tcx.hir().local_def_id(c.hir_id);
- let ct = ty::Const::from_anon_const(self.tcx, def_id);
+ let ct = ty::Const::from_anon_const(self.tcx, c.def_id);
if let ty::ConstKind::Unevaluated(_) = ct.kind() {
- let span = self.tcx.hir().span(c.hir_id);
+ let span = self.tcx.def_span(c.def_id);
self.preds.insert((
ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct))
.to_predicate(self.tcx),
@@ -408,11 +424,13 @@ pub(super) fn explicit_predicates_of<'tcx>(
.iter()
.copied()
.filter(|(pred, _)| match pred.kind().skip_binder() {
- ty::PredicateKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
- ty::PredicateKind::Projection(proj) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => !is_assoc_item_ty(tr.self_ty()),
+ ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => {
!is_assoc_item_ty(proj.projection_ty.self_ty())
}
- ty::PredicateKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
+ ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => {
+ !is_assoc_item_ty(outlives.0)
+ }
_ => true,
})
.collect();
@@ -427,7 +445,9 @@ pub(super) fn explicit_predicates_of<'tcx>(
} else {
if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- if tcx.hir().opt_const_param_default_param_hir_id(hir_id).is_some() {
+ let parent_def_id = tcx.hir().get_parent_item(hir_id);
+
+ if tcx.hir().opt_const_param_default_param_def_id(hir_id).is_some() {
// In `generics_of` we set the generics' parent to be our parent's parent which means that
// we lose out on the predicates of our actual parent if we dont return those predicates here.
// (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
@@ -439,8 +459,33 @@ pub(super) fn explicit_predicates_of<'tcx>(
// parent of generics returned by `generics_of`
//
// In the above code we want the anon const to have predicates in its param env for `T: Trait`
- let item_def_id = tcx.hir().get_parent_item(hir_id);
- // In the above code example we would be calling `explicit_predicates_of(Foo)` here
+ // and we would be calling `explicit_predicates_of(Foo)` here
+ return tcx.explicit_predicates_of(parent_def_id);
+ }
+
+ let parent_def_kind = tcx.def_kind(parent_def_id);
+ if matches!(parent_def_kind, DefKind::OpaqueTy) {
+ // In `instantiate_identity` we inherit the predicates of our parent.
+ // However, opaque types do not have a parent (see `gather_explicit_predicates_of`), which means
+ // that we lose out on the predicates of our actual parent if we dont return those predicates here.
+ //
+ //
+ // fn foo<T: Trait>() -> impl Iterator<Output = Another<{ <T as Trait>::ASSOC }> > { todo!() }
+ // ^^^^^^^^^^^^^^^^^^^ the def id we are calling
+ // explicit_predicates_of on
+ //
+ // In the above code we want the anon const to have predicates in its param env for `T: Trait`.
+ // However, the anon const cannot inherit predicates from its parent since it's opaque.
+ //
+ // To fix this, we call `explicit_predicates_of` directly on `foo`, the parent's parent.
+
+ // In the above example this is `foo::{opaque#0}` or `impl Iterator`
+ let parent_hir_id = tcx.hir().local_def_id_to_hir_id(parent_def_id.def_id);
+
+ // In the above example this is the function `foo`
+ let item_def_id = tcx.hir().get_parent_item(parent_hir_id);
+
+ // In the above code example we would be calling `explicit_predicates_of(foo)` here
return tcx.explicit_predicates_of(item_def_id);
}
}
@@ -504,7 +549,7 @@ pub(super) fn super_predicates_that_define_assoc_type(
let is_trait_alias = tcx.is_trait_alias(trait_def_id);
let superbounds2 = icx.type_parameter_bounds_in_generics(
generics,
- item.hir_id(),
+ item.owner_id.def_id,
self_param_ty,
OnlySelfBounds(!is_trait_alias),
assoc_name,
@@ -521,7 +566,9 @@ pub(super) fn super_predicates_that_define_assoc_type(
// which will, in turn, reach indirect supertraits.
for &(pred, span) in superbounds {
debug!("superbound: {:?}", pred);
- if let ty::PredicateKind::Trait(bound) = pred.kind().skip_binder() {
+ if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) =
+ pred.kind().skip_binder()
+ {
tcx.at(span).super_predicates_of(bound.def_id());
}
}
@@ -614,14 +661,14 @@ pub(super) fn type_param_predicates(
let extra_predicates = extend.into_iter().chain(
icx.type_parameter_bounds_in_generics(
ast_generics,
- param_id,
+ def_id,
ty,
OnlySelfBounds(true),
Some(assoc_name),
)
.into_iter()
.filter(|(predicate, _)| match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(data) => data.self_ty().is_param(index),
+ ty::PredicateKind::Clause(ty::Clause::Trait(data)) => data.self_ty().is_param(index),
_ => false,
}),
);
@@ -639,13 +686,11 @@ impl<'tcx> ItemCtxt<'tcx> {
fn type_parameter_bounds_in_generics(
&self,
ast_generics: &'tcx hir::Generics<'tcx>,
- param_id: hir::HirId,
+ param_def_id: LocalDefId,
ty: Ty<'tcx>,
only_self_bounds: OnlySelfBounds,
assoc_name: Option<Ident>,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
- let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
- trace!(?param_def_id);
ast_generics
.predicates
.iter()
@@ -654,7 +699,7 @@ impl<'tcx> ItemCtxt<'tcx> {
_ => None,
})
.flat_map(|bp| {
- let bt = if bp.is_param_bound(param_def_id) {
+ let bt = if bp.is_param_bound(param_def_id.to_def_id()) {
Some(ty)
} else if !only_self_bounds.0 {
Some(self.to_ty(bp.bounded_ty))
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index c29a645eb..9bd1715ce 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -514,10 +514,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
}
Node::GenericParam(&GenericParam {
- hir_id: param_hir_id,
+ def_id: param_def_id,
kind: GenericParamKind::Const { default: Some(ct), .. },
..
- }) if ct.hir_id == hir_id => tcx.type_of(tcx.hir().local_def_id(param_hir_id)),
+ }) if ct.hir_id == hir_id => tcx.type_of(param_def_id),
x => tcx.ty_error_with_message(
DUMMY_SP,
@@ -636,9 +636,8 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
self.tcx.hir()
}
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
- if let hir::ExprKind::Closure { .. } = ex.kind {
- let def_id = self.tcx.hir().local_def_id(ex.hir_id);
- self.check(def_id);
+ if let hir::ExprKind::Closure(closure) = ex.kind {
+ self.check(closure.def_id);
}
intravisit::walk_expr(self, ex);
}
@@ -698,7 +697,7 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
}
let Some(hidden) = locator.found else {
- tcx.sess.emit_err(UnconstrainedOpaqueType {
+ let reported = tcx.sess.emit_err(UnconstrainedOpaqueType {
span: tcx.def_span(def_id),
name: tcx.item_name(tcx.local_parent(def_id).to_def_id()),
what: match tcx.hir().get(scope) {
@@ -708,7 +707,7 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
_ => "item",
},
});
- return tcx.ty_error();
+ return tcx.ty_error_with_guaranteed(reported);
};
// Only check against typeck if we didn't already error
@@ -771,9 +770,8 @@ fn find_opaque_ty_constraints_for_rpit(
self.tcx.hir()
}
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
- if let hir::ExprKind::Closure { .. } = ex.kind {
- let def_id = self.tcx.hir().local_def_id(ex.hir_id);
- self.check(def_id);
+ if let hir::ExprKind::Closure(closure) = ex.kind {
+ self.check(closure.def_id);
}
intravisit::walk_expr(self, ex);
}
diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index 213b89fc7..b4057df78 100644
--- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -187,7 +187,8 @@ pub fn setup_constraining_predicates<'tcx>(
for j in i..predicates.len() {
// Note that we don't have to care about binders here,
// as the impl trait ref never contains any late-bound regions.
- if let ty::PredicateKind::Projection(projection) = predicates[j].0.kind().skip_binder()
+ if let ty::PredicateKind::Clause(ty::Clause::Projection(projection)) =
+ predicates[j].0.kind().skip_binder()
{
// Special case: watch out for some kind of sneaky attempt
// to project out an associated type defined by this very
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index d5b1a7ce1..c92ab749b 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -43,6 +43,10 @@ pub struct LifetimesOrBoundsMismatchOnTrait {
pub span: Span,
#[label(generics_label)]
pub generics_span: Option<Span>,
+ #[label(where_label)]
+ pub where_span: Option<Span>,
+ #[label(bounds_label)]
+ pub bounds_span: Vec<Span>,
pub item_kind: &'static str,
pub ident: Ident,
}
@@ -120,7 +124,7 @@ pub struct TypeofReservedKeywordUsed<'tcx> {
#[primary_span]
#[label]
pub span: Span,
- #[suggestion_verbose(code = "{ty}")]
+ #[suggestion(style = "verbose", code = "{ty}")]
pub opt_sugg: Option<(Span, Applicability)>,
}
@@ -156,6 +160,7 @@ pub struct MissingTypeParams {
// Manual implementation of `IntoDiagnostic` to be able to call `span_to_snippet`.
impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
+ #[track_caller]
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut err = handler.struct_span_err_with_code(
self.span,
@@ -238,7 +243,11 @@ pub struct UnusedExternCrate {
#[derive(LintDiagnostic)]
#[diag(hir_analysis_extern_crate_not_idiomatic)]
pub struct ExternCrateNotIdiomatic {
- #[suggestion_short(applicability = "machine-applicable", code = "{suggestion_code}")]
+ #[suggestion(
+ style = "short",
+ applicability = "machine-applicable",
+ code = "{suggestion_code}"
+ )]
pub span: Span,
pub msg_code: String,
pub suggestion_code: String,
@@ -280,3 +289,10 @@ pub struct SelfInImplSelf {
#[note]
pub note: (),
}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_linkage_type, code = "E0791")]
+pub(crate) struct LinkageType {
+ #[primary_span]
+ pub span: Span,
+}
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index b0fdfcf38..4f9d58265 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -5,7 +5,7 @@ use rustc_hir::{ForeignItem, ForeignItemKind, HirId};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{ObligationCause, WellFormedLoc};
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, Region, ToPredicate, TyCtxt, TypeFoldable, TypeFolder};
+use rustc_middle::ty::{self, Region, TyCtxt, TypeFoldable, TypeFolder};
use rustc_trait_selection::traits;
pub fn provide(providers: &mut Providers) {
@@ -74,10 +74,10 @@ fn diagnostic_hir_wf_check<'tcx>(
let errors = traits::fully_solve_obligation(
&infcx,
traits::Obligation::new(
+ self.tcx,
cause,
self.param_env,
- ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into()))
- .to_predicate(self.tcx),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into())),
),
);
if !errors.is_empty() {
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 e806e9487..fd8e8ed7b 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
@@ -69,6 +69,7 @@ use crate::constrained_generic_params as cgp;
use crate::errors::SubstsOnOverriddenImpl;
use rustc_data_structures::fx::FxHashSet;
+use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::TyCtxtInferExt;
@@ -80,6 +81,7 @@ use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt};
+use tracing::instrument;
pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
if let Some(node) = parent_specialization_node(tcx, impl_def_id) {
@@ -103,13 +105,11 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti
}
/// Check that `impl1` is a sound specialization
+#[instrument(level = "debug", skip(tcx))]
fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node) {
if let Some((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) {
let impl2_def_id = impl2_node.def_id();
- debug!(
- "check_always_applicable(\nimpl1_def_id={:?},\nimpl2_def_id={:?},\nimpl2_substs={:?}\n)",
- impl1_def_id, impl2_def_id, impl2_substs
- );
+ debug!(?impl2_def_id, ?impl2_substs);
let parent_substs = if impl2_node.is_from_trait() {
impl2_substs.to_vec()
@@ -118,12 +118,33 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
};
let span = tcx.def_span(impl1_def_id);
+ check_constness(tcx, impl1_def_id, impl2_node, span);
check_static_lifetimes(tcx, &parent_substs, span);
check_duplicate_params(tcx, impl1_substs, &parent_substs, span);
check_predicates(tcx, impl1_def_id, impl1_substs, impl2_node, impl2_substs, span);
}
}
+/// Check that the specializing impl `impl1` is at least as const as the base
+/// impl `impl2`
+fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) {
+ if impl2_node.is_from_trait() {
+ // This isn't a specialization
+ return;
+ }
+
+ let impl1_constness = tcx.constness(impl1_def_id.to_def_id());
+ let impl2_constness = tcx.constness(impl2_node.def_id());
+
+ if let hir::Constness::Const = impl2_constness {
+ if let hir::Constness::NotConst = impl1_constness {
+ tcx.sess
+ .struct_span_err(span, "cannot specialize on const impl with non-const impl")
+ .emit();
+ }
+ }
+}
+
/// Given a specializing impl `impl1`, and the base impl `impl2`, returns two
/// substitutions `(S1, S2)` that equate their trait references. The returned
/// types are expressed in terms of the generics of `impl1`.
@@ -155,7 +176,7 @@ fn get_impl_substs<'tcx>(
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- ocx.infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ ocx.infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return None;
}
@@ -193,7 +214,9 @@ fn unconstrained_parent_impl_substs<'tcx>(
// the functions in `cgp` add the constrained parameters to a list of
// unconstrained parameters.
for (predicate, _) in impl_generic_predicates.predicates.iter() {
- if let ty::PredicateKind::Projection(proj) = predicate.kind().skip_binder() {
+ if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) =
+ predicate.kind().skip_binder()
+ {
let projection_ty = proj.projection_ty;
let projected_ty = proj.term;
@@ -278,15 +301,15 @@ fn check_static_lifetimes<'tcx>(
/// Check whether predicates on the specializing impl (`impl1`) are allowed.
///
-/// Each predicate `P` must be:
+/// Each predicate `P` must be one of:
///
-/// * global (not reference any parameters)
-/// * `T: Tr` predicate where `Tr` is an always-applicable trait
-/// * on the base `impl impl2`
-/// * Currently this check is done using syntactic equality, which is
-/// conservative but generally sufficient.
-/// * a well-formed predicate of a type argument of the trait being implemented,
+/// * Global (not reference any parameters).
+/// * A `T: Tr` predicate where `Tr` is an always-applicable trait.
+/// * Present on the base impl `impl2`.
+/// * This check is done using the `trait_predicates_eq` function below.
+/// * A well-formed predicate of a type argument of the trait being implemented,
/// including the `Self`-type.
+#[instrument(level = "debug", skip(tcx))]
fn check_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
impl1_def_id: LocalDefId,
@@ -322,10 +345,7 @@ fn check_predicates<'tcx>(
.map(|obligation| obligation.predicate)
.collect()
};
- debug!(
- "check_always_applicable(\nimpl1_predicates={:?},\nimpl2_predicates={:?}\n)",
- impl1_predicates, impl2_predicates,
- );
+ debug!(?impl1_predicates, ?impl2_predicates);
// Since impls of always applicable traits don't get to assume anything, we
// can also assume their supertraits apply.
@@ -373,25 +393,90 @@ fn check_predicates<'tcx>(
);
for (predicate, span) in impl1_predicates {
- if !impl2_predicates.contains(&predicate) {
+ if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(tcx, predicate, *pred2, span)) {
check_specialization_on(tcx, predicate, span)
}
}
}
+/// Checks if some predicate on the specializing impl (`predicate1`) is the same
+/// as some predicate on the base impl (`predicate2`).
+///
+/// This basically just checks syntactic equivalence, but is a little more
+/// forgiving since we want to equate `T: Tr` with `T: ~const Tr` so this can work:
+///
+/// ```ignore (illustrative)
+/// #[rustc_specialization_trait]
+/// trait Specialize { }
+///
+/// impl<T: Bound> Tr for T { }
+/// impl<T: ~const Bound + Specialize> const Tr for T { }
+/// ```
+///
+/// However, we *don't* want to allow the reverse, i.e., when the bound on the
+/// specializing impl is not as const as the bound on the base impl:
+///
+/// ```ignore (illustrative)
+/// impl<T: ~const Bound> const Tr for T { }
+/// impl<T: Bound + Specialize> const Tr for T { } // should be T: ~const Bound
+/// ```
+///
+/// So we make that check in this function and try to raise a helpful error message.
+fn trait_predicates_eq<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ predicate1: ty::Predicate<'tcx>,
+ predicate2: ty::Predicate<'tcx>,
+ span: Span,
+) -> bool {
+ let pred1_kind = predicate1.kind().skip_binder();
+ let pred2_kind = predicate2.kind().skip_binder();
+ let (trait_pred1, trait_pred2) = match (pred1_kind, pred2_kind) {
+ (
+ ty::PredicateKind::Clause(ty::Clause::Trait(pred1)),
+ ty::PredicateKind::Clause(ty::Clause::Trait(pred2)),
+ ) => (pred1, pred2),
+ // Just use plain syntactic equivalence if either of the predicates aren't
+ // trait predicates or have bound vars.
+ _ => return predicate1 == predicate2,
+ };
+
+ let predicates_equal_modulo_constness = {
+ let pred1_unconsted =
+ ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..trait_pred1 };
+ let pred2_unconsted =
+ ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..trait_pred2 };
+ pred1_unconsted == pred2_unconsted
+ };
+
+ if !predicates_equal_modulo_constness {
+ return false;
+ }
+
+ // Check that the predicate on the specializing impl is at least as const as
+ // the one on the base.
+ match (trait_pred2.constness, trait_pred1.constness) {
+ (ty::BoundConstness::ConstIfConst, ty::BoundConstness::NotConst) => {
+ tcx.sess.struct_span_err(span, "missing `~const` qualifier for specialization").emit();
+ }
+ _ => {}
+ }
+
+ true
+}
+
+#[instrument(level = "debug", skip(tcx))]
fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>, span: Span) {
- debug!("can_specialize_on(predicate = {:?})", predicate);
match predicate.kind().skip_binder() {
// Global predicates are either always true or always false, so we
// are fine to specialize on.
_ if predicate.is_global() => (),
// We allow specializing on explicitly marked traits with no associated
// items.
- ty::PredicateKind::Trait(ty::TraitPredicate {
+ ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
trait_ref,
- constness: ty::BoundConstness::NotConst,
+ constness: _,
polarity: _,
- }) => {
+ })) => {
if !matches!(
trait_predicate_kind(tcx, predicate),
Some(TraitSpecializationKind::Marker)
@@ -407,7 +492,10 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
.emit();
}
}
- ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
+ ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate {
+ projection_ty,
+ term,
+ })) => {
tcx.sess
.struct_span_err(
span,
@@ -428,12 +516,14 @@ fn trait_predicate_kind<'tcx>(
predicate: ty::Predicate<'tcx>,
) -> Option<TraitSpecializationKind> {
match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _ }) => {
- Some(tcx.trait_def(trait_ref.def_id).specialization_kind)
- }
- ty::PredicateKind::RegionOutlives(_)
- | ty::PredicateKind::TypeOutlives(_)
- | ty::PredicateKind::Projection(_)
+ ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
+ trait_ref,
+ constness: _,
+ polarity: _,
+ })) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
+ ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_))
+ | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_))
+ | ty::PredicateKind::Clause(ty::Clause::Projection(_))
| ty::PredicateKind::WellFormed(_)
| ty::PredicateKind::Subtype(_)
| ty::PredicateKind::Coerce(_)
@@ -441,6 +531,7 @@ fn trait_predicate_kind<'tcx>(
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::Ambiguous
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
}
}
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 525cd2419..2058832d5 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -106,7 +106,7 @@ use rustc_middle::middle;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::util;
-use rustc_session::config::EntryFnType;
+use rustc_session::{config::EntryFnType, parse::feature_err};
use rustc_span::{symbol::sym, Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
@@ -118,20 +118,40 @@ use astconv::AstConv;
use bounds::Bounds;
fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
- match (decl.c_variadic, abi) {
- // The function has the correct calling convention, or isn't a "C-variadic" function.
- (false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl { .. }) => {}
- // The function is a "C-variadic" function with an incorrect calling convention.
- (true, _) => {
- let mut err = struct_span_err!(
- tcx.sess,
+ const ERROR_HEAD: &str = "C-variadic function must have a compatible calling convention";
+ const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `win64`, `sysv64` or `efiapi`";
+ const CONVENTIONS_STABLE: &str = "`C` or `cdecl`";
+ const UNSTABLE_EXPLAIN: &str =
+ "using calling conventions other than `C` or `cdecl` for varargs functions is unstable";
+
+ if !decl.c_variadic || matches!(abi, Abi::C { .. } | Abi::Cdecl { .. }) {
+ return;
+ }
+
+ let extended_abi_support = tcx.features().extended_varargs_abi_support;
+ let conventions = match (extended_abi_support, abi.supports_varargs()) {
+ // User enabled additional ABI support for varargs and function ABI matches those ones.
+ (true, true) => return,
+
+ // Using this ABI would be ok, if the feature for additional ABI support was enabled.
+ // Return CONVENTIONS_STABLE, because we want the other error to look the same.
+ (false, true) => {
+ feature_err(
+ &tcx.sess.parse_sess,
+ sym::extended_varargs_abi_support,
span,
- E0045,
- "C-variadic function must have C or cdecl calling convention"
- );
- err.span_label(span, "C-variadics require C or cdecl calling convention").emit();
+ UNSTABLE_EXPLAIN,
+ )
+ .emit();
+ CONVENTIONS_STABLE
}
- }
+
+ (false, false) => CONVENTIONS_STABLE,
+ (true, false) => CONVENTIONS_UNSTABLE,
+ };
+
+ let mut err = struct_span_err!(tcx.sess, span, E0045, "{}, like {}", ERROR_HEAD, conventions);
+ err.span_label(span, ERROR_HEAD).emit();
}
fn require_same_types<'tcx>(
@@ -153,7 +173,7 @@ fn require_same_types<'tcx>(
match &errors[..] {
[] => true,
errors => {
- infcx.err_ctxt().report_fulfillment_errors(errors, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(errors, None);
false
}
}
@@ -312,11 +332,11 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
ObligationCauseCode::MainFunctionType,
);
let ocx = traits::ObligationCtxt::new(&infcx);
- let norm_return_ty = ocx.normalize(cause.clone(), param_env, return_ty);
+ let norm_return_ty = ocx.normalize(&cause, param_env, return_ty);
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, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None);
error = true;
}
// now we can take the return type of the given main function
diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index 7534482cc..663f1c49d 100644
--- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
@@ -30,28 +30,30 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
// process predicates and convert to `RequiredPredicates` entry, see below
for &(predicate, span) in predicates.predicates {
match predicate.kind().skip_binder() {
- ty::PredicateKind::TypeOutlives(OutlivesPredicate(ty, reg)) => {
- insert_outlives_predicate(
- tcx,
- ty.into(),
- reg,
- span,
- &mut required_predicates,
- )
- }
+ ty::PredicateKind::Clause(ty::Clause::TypeOutlives(OutlivesPredicate(
+ ty,
+ reg,
+ ))) => insert_outlives_predicate(
+ tcx,
+ ty.into(),
+ reg,
+ span,
+ &mut required_predicates,
+ ),
- ty::PredicateKind::RegionOutlives(OutlivesPredicate(reg1, reg2)) => {
- insert_outlives_predicate(
- tcx,
- reg1.into(),
- reg2,
- span,
- &mut required_predicates,
- )
- }
+ ty::PredicateKind::Clause(ty::Clause::RegionOutlives(OutlivesPredicate(
+ reg1,
+ reg2,
+ ))) => insert_outlives_predicate(
+ tcx,
+ reg1.into(),
+ reg2,
+ span,
+ &mut required_predicates,
+ ),
- ty::PredicateKind::Trait(..)
- | ty::PredicateKind::Projection(..)
+ ty::PredicateKind::Clause(ty::Clause::Trait(..))
+ | ty::PredicateKind::Clause(ty::Clause::Projection(..))
| ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
@@ -59,6 +61,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::Ambiguous
| ty::PredicateKind::TypeWellFormedFromEnv(..) => (),
}
}
diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs
index e50c26765..81fe32000 100644
--- a/compiler/rustc_hir_analysis/src/outlives/mod.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs
@@ -3,7 +3,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, CratePredicatesMap, ToPredicate, TyCtxt};
+use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt};
use rustc_span::symbol::sym;
use rustc_span::Span;
@@ -17,12 +17,12 @@ pub fn provide(providers: &mut Providers) {
*providers = Providers { inferred_outlives_of, inferred_outlives_crate, ..*providers };
}
-fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate<'_>, Span)] {
+fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Clause<'_>, Span)] {
let id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local());
if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization()
{
- if tcx.hir().opt_const_param_default_param_hir_id(id).is_some() {
+ if tcx.hir().opt_const_param_default_param_def_id(id).is_some() {
// In `generics_of` we set the generics' parent to be our parent's parent which means that
// we lose out on the predicates of our actual parent if we dont return those predicates here.
// (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
@@ -50,10 +50,10 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate
if tcx.has_attr(item_def_id, sym::rustc_outlives) {
let mut pred: Vec<String> = predicates
.iter()
- .map(|(out_pred, _)| match out_pred.kind().skip_binder() {
- ty::PredicateKind::RegionOutlives(p) => p.to_string(),
- ty::PredicateKind::TypeOutlives(p) => p.to_string(),
- err => bug!("unexpected predicate {:?}", err),
+ .map(|(out_pred, _)| match out_pred {
+ ty::Clause::RegionOutlives(p) => p.to_string(),
+ ty::Clause::TypeOutlives(p) => p.to_string(),
+ err => bug!("unexpected clause {:?}", err),
})
.collect();
pred.sort();
@@ -101,17 +101,11 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> {
|(ty::OutlivesPredicate(kind1, region2), &span)| {
match kind1.unpack() {
GenericArgKind::Type(ty1) => Some((
- ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
- ty::OutlivesPredicate(ty1, *region2),
- ))
- .to_predicate(tcx),
+ ty::Clause::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)),
span,
)),
GenericArgKind::Lifetime(region1) => Some((
- ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
- ty::OutlivesPredicate(region1, *region2),
- ))
- .to_predicate(tcx),
+ ty::Clause::RegionOutlives(ty::OutlivesPredicate(region1, *region2)),
span,
)),
GenericArgKind::Const(_) => {
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 435912464..4451db19f 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
@@ -296,25 +296,35 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
) -> String {
debug!(?path_hir_id);
+ // If there was already a lifetime among the arguments, just replicate that one.
+ if let Some(lt) = self.gen_args.args.iter().find_map(|arg| match arg {
+ hir::GenericArg::Lifetime(lt) => Some(lt),
+ _ => None,
+ }) {
+ return std::iter::repeat(lt.to_string())
+ .take(num_params_to_take)
+ .collect::<Vec<_>>()
+ .join(", ");
+ }
+
let mut ret = Vec::new();
+ let mut ty_id = None;
for (id, node) in self.tcx.hir().parent_iter(path_hir_id) {
debug!(?id);
- let params = if let Some(generics) = node.generics() {
- generics.params
- } else if let hir::Node::Ty(ty) = node
- && let hir::TyKind::BareFn(bare_fn) = ty.kind
- {
- bare_fn.generic_params
- } else {
- &[]
- };
- ret.extend(params.iter().filter_map(|p| {
- let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
- = p.kind
- else { return None };
- let hir::ParamName::Plain(name) = p.name else { return None };
- Some(name.to_string())
- }));
+ if let hir::Node::Ty(_) = node {
+ ty_id = Some(id);
+ }
+
+ // Suggest `'_` when in function parameter or elided function return.
+ 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);
+
+ if in_arg || (in_ret && fn_decl.lifetime_elision_allowed) {
+ return std::iter::repeat("'_".to_owned()).take(num_params_to_take).collect::<Vec<_>>().join(", ");
+ }
+ }
+
// Suggest `'static` when in const/static item-like.
if let hir::Node::Item(hir::Item {
kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. },
@@ -334,11 +344,29 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
})
| hir::Node::AnonConst(..) = node
{
- ret.extend(
- std::iter::repeat("'static".to_owned())
- .take(num_params_to_take.saturating_sub(ret.len())),
- );
+ return std::iter::repeat("'static".to_owned())
+ .take(num_params_to_take.saturating_sub(ret.len()))
+ .collect::<Vec<_>>()
+ .join(", ");
}
+
+ let params = if let Some(generics) = node.generics() {
+ generics.params
+ } else if let hir::Node::Ty(ty) = node
+ && let hir::TyKind::BareFn(bare_fn) = ty.kind
+ {
+ bare_fn.generic_params
+ } else {
+ &[]
+ };
+ ret.extend(params.iter().filter_map(|p| {
+ let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
+ = p.kind
+ else { return None };
+ let hir::ParamName::Plain(name) = p.name else { return None };
+ Some(name.to_string())
+ }));
+
if ret.len() >= num_params_to_take {
return ret[..num_params_to_take].join(", ");
}
@@ -728,7 +756,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
&& 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_assoc_fn_excess_args == num_trait_generics_except_self - num_generic_args_supplied_to_trait {
+ 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 sugg = vec![
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index eaf0310d5..6ce0c18bf 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -72,8 +72,8 @@ pub fn add_constraints_from_crate<'a, 'tcx>(
let adt = tcx.adt_def(def_id);
for variant in adt.variants() {
- if let Some(ctor) = variant.ctor_def_id {
- constraint_cx.build_constraints_for_item(ctor.expect_local());
+ if let Some(ctor_def_id) = variant.ctor_def_id() {
+ constraint_cx.build_constraints_for_item(ctor_def_id.expect_local());
}
}
}
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 82103c5a0..8b2719c2f 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -5,9 +5,11 @@
use rustc_arena::DroplessArena;
use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, CrateVariancesMap, TyCtxt};
+use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt};
+use rustc_middle::ty::{DefIdTree, TypeSuperVisitable, TypeVisitable};
+use std::ops::ControlFlow;
/// Defines the `TermsContext` basically houses an arena where we can
/// allocate terms.
@@ -50,6 +52,9 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] {
| DefKind::Union
| DefKind::Variant
| DefKind::Ctor(..) => {}
+ DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder => {
+ return variance_of_opaque(tcx, item_def_id.expect_local());
+ }
_ => {
// Variance not relevant.
span_bug!(tcx.def_span(item_def_id), "asked to compute variance for wrong kind of item")
@@ -61,3 +66,125 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] {
let crate_map = tcx.crate_variances(());
crate_map.variances.get(&item_def_id).copied().unwrap_or(&[])
}
+
+#[instrument(level = "trace", skip(tcx), ret)]
+fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
+ let generics = tcx.generics_of(item_def_id);
+
+ // Opaque types may only use regions that are bound. So for
+ // ```rust
+ // type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
+ // ```
+ // we may not use `'c` in the hidden type.
+ struct OpaqueTypeLifetimeCollector<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ root_def_id: DefId,
+ variances: Vec<ty::Variance>,
+ }
+
+ impl<'tcx> OpaqueTypeLifetimeCollector<'tcx> {
+ #[instrument(level = "trace", skip(self), ret)]
+ fn visit_opaque(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> ControlFlow<!> {
+ if def_id != self.root_def_id && self.tcx.is_descendant_of(def_id, self.root_def_id) {
+ let child_variances = self.tcx.variances_of(def_id);
+ for (a, v) in substs.iter().zip(child_variances) {
+ if *v != ty::Bivariant {
+ a.visit_with(self)?;
+ }
+ }
+ ControlFlow::CONTINUE
+ } else {
+ substs.visit_with(self)
+ }
+ }
+ }
+
+ impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> {
+ #[instrument(level = "trace", skip(self), ret)]
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() {
+ self.variances[ebr.index as usize] = ty::Invariant;
+ }
+ r.super_visit_with(self)
+ }
+
+ #[instrument(level = "trace", skip(self), ret)]
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match t.kind() {
+ ty::Opaque(def_id, substs) => self.visit_opaque(*def_id, substs),
+ ty::Projection(proj)
+ if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
+ {
+ self.visit_opaque(proj.item_def_id, proj.substs)
+ }
+ _ => t.super_visit_with(self),
+ }
+ }
+ }
+
+ // By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt
+ // lifetime generics.
+ let mut variances: Vec<_> = std::iter::repeat(ty::Invariant).take(generics.count()).collect();
+
+ // Mark all lifetimes from parent generics as unused (Bivariant).
+ // This will be overridden later if required.
+ {
+ let mut generics = generics;
+ while let Some(def_id) = generics.parent {
+ generics = tcx.generics_of(def_id);
+ for param in &generics.params {
+ match param.kind {
+ ty::GenericParamDefKind::Lifetime => {
+ variances[param.index as usize] = ty::Bivariant;
+ }
+ ty::GenericParamDefKind::Type { .. }
+ | ty::GenericParamDefKind::Const { .. } => {}
+ }
+ }
+ }
+ }
+
+ let mut collector =
+ OpaqueTypeLifetimeCollector { tcx, root_def_id: item_def_id.to_def_id(), variances };
+ let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id.to_def_id());
+ for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() {
+ let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs);
+ debug!(?pred);
+
+ // We only ignore opaque type substs if the opaque type is the outermost type.
+ // The opaque type may be nested within itself via recursion in e.g.
+ // type Foo<'a> = impl PartialEq<Foo<'a>>;
+ // which thus mentions `'a` and should thus accept hidden types that borrow 'a
+ // instead of requiring an additional `+ 'a`.
+ match pred.kind().skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
+ trait_ref: ty::TraitRef { def_id: _, substs },
+ constness: _,
+ polarity: _,
+ })) => {
+ for subst in &substs[1..] {
+ subst.visit_with(&mut collector);
+ }
+ }
+ ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate {
+ projection_ty: ty::ProjectionTy { substs, item_def_id: _ },
+ term,
+ })) => {
+ for subst in &substs[1..] {
+ subst.visit_with(&mut collector);
+ }
+ term.visit_with(&mut collector);
+ }
+ ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
+ _,
+ region,
+ ))) => {
+ region.visit_with(&mut collector);
+ }
+ _ => {
+ pred.visit_with(&mut collector);
+ }
+ }
+ }
+ tcx.arena.alloc_from_iter(collector.variances.into_iter())
+}
diff --git a/compiler/rustc_hir_analysis/src/variance/terms.rs b/compiler/rustc_hir_analysis/src/variance/terms.rs
index 1f763011e..3b286bb9c 100644
--- a/compiler/rustc_hir_analysis/src/variance/terms.rs
+++ b/compiler/rustc_hir_analysis/src/variance/terms.rs
@@ -42,22 +42,22 @@ impl<'a> fmt::Debug for VarianceTerm<'a> {
}
}
-// The first pass over the crate simply builds up the set of inferreds.
+/// The first pass over the crate simply builds up the set of inferreds.
pub struct TermsContext<'a, 'tcx> {
pub tcx: TyCtxt<'tcx>,
pub arena: &'a DroplessArena,
- // For marker types, UnsafeCell, and other lang items where
- // variance is hardcoded, records the item-id and the hardcoded
- // variance.
+ /// For marker types, `UnsafeCell`, and other lang items where
+ /// variance is hardcoded, records the item-id and the hardcoded
+ /// variance.
pub lang_items: Vec<(LocalDefId, Vec<ty::Variance>)>,
- // Maps from the node id of an item to the first inferred index
- // used for its type & region parameters.
+ /// Maps from the node id of an item to the first inferred index
+ /// used for its type & region parameters.
pub inferred_starts: LocalDefIdMap<InferredIndex>,
- // Maps from an InferredIndex to the term for that variable.
+ /// Maps from an InferredIndex to the term for that variable.
pub inferred_terms: Vec<VarianceTermPtr<'a>>,
}
@@ -91,8 +91,8 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(
let adt = tcx.adt_def(def_id);
for variant in adt.variants() {
- if let Some(ctor) = variant.ctor_def_id {
- terms_cx.add_inferreds_for_item(ctor.expect_local());
+ if let Some(ctor_def_id) = variant.ctor_def_id() {
+ terms_cx.add_inferreds_for_item(ctor_def_id.expect_local());
}
}
}