+use crate::check::regionck::OutlivesEnvironmentExt;
use crate::check::{FnCtxt, Inherited};
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
-use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir::itemlikevisit::ParItemLikeVisitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::ItemKind;
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::outlives::obligations::TypeOutlives;
use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{self, RegionckMode, SubregionOrigin};
use rustc_middle::hir::map as hir_map;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
use rustc_middle::ty::trait_def::TraitSpecializationKind;
};
use rustc_session::parse::feature_err;
use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc};
return;
}
let associated_items: &ty::AssocItems<'_> = tcx.associated_items(encl_trait_def_id);
+ let mut clauses = FxHashSet::default();
// For every function in this trait...
for item in
associated_items.in_definition_order().filter(|item| matches!(item.kind, ty::AssocKind::Fn))
{
- tcx.infer_ctxt().enter(|infcx| {
- let sig: ty::Binder<'_, ty::FnSig<'_>> = tcx.fn_sig(item.def_id);
- let sig = infcx.replace_bound_vars_with_placeholders(sig);
- // Find out what regions are passed as GAT substs
- let mut visitor = GATSubstCollector {
- tcx,
- gat: trait_item.def_id.to_def_id(),
- regions: FxHashSet::default(),
- _types: FxHashSet::default(),
- };
- sig.output().visit_with(&mut visitor);
- // If there are none, then it nothing to do
- if visitor.regions.is_empty() {
- return;
- }
- let mut clauses = FxHashSet::default();
- // Otherwise, find the clauses required from implied bounds
- for input in sig.inputs() {
- // For a given input type, find the implied bounds
- let TypeOpOutput { output: bounds, .. } = match ty::ParamEnv::empty()
- .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty: input })
- .fully_perform(&infcx)
- {
- Ok(o) => o,
- Err(_) => continue,
- };
- debug!(?bounds);
- for bound in bounds {
- match bound {
- traits::query::OutlivesBound::RegionSubParam(r, p) => {
- // If the implied bound is a `RegionSubParam` and
- // the region is used a GAT subst...
- for idx in visitor
- .regions
- .iter()
- .filter(|(proj_r, _)| proj_r == &r)
- .map(|r| r.1)
- {
- // Then create a clause that is required on the GAT
- let param_r = tcx.mk_region(ty::RegionKind::ReEarlyBound(
- ty::EarlyBoundRegion {
- def_id: generics.params[idx].def_id,
- index: idx as u32,
- name: generics.params[idx].name,
- },
- ));
- let clause = ty::PredicateKind::TypeOutlives(
- ty::OutlivesPredicate(tcx.mk_ty(ty::Param(p)), param_r),
- );
- let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
- clauses.insert(clause);
- }
- }
- _ => {}
- }
- }
- }
- // If there are any missing clauses, emit an error
- debug!(?clauses);
- if !clauses.is_empty() {
- let written_predicates: ty::GenericPredicates<'_> =
- tcx.predicates_of(trait_item.def_id);
- for clause in clauses {
- let found =
- written_predicates.predicates.iter().find(|p| p.0 == clause).is_some();
- debug!(?clause, ?found);
- let mut error = tcx.sess.struct_span_err(
- trait_item.generics.span,
- &format!("Missing bound: {}", clause),
+ let id = hir::HirId::make_owner(item.def_id.expect_local());
+ let span = DUMMY_SP;
+ let param_env = tcx.param_env(item.def_id.expect_local());
+
+ let sig = tcx.fn_sig(item.def_id);
+ let sig = tcx.liberate_late_bound_regions(item.def_id, sig);
+ let mut visitor = GATSubstCollector {
+ tcx,
+ gat: trait_item.def_id.to_def_id(),
+ regions: FxHashSet::default(),
+ types: FxHashSet::default(),
+ };
+ sig.output().visit_with(&mut visitor);
+ let mut wf_tys = FxHashSet::default();
+ wf_tys.extend(sig.inputs());
+ // FIXME: normalize and add normalized inputs?
+
+ for (region, region_idx) in &visitor.regions {
+ for (ty, ty_idx) in &visitor.types {
+ tcx.infer_ctxt().enter(|infcx| {
+ let mut outlives_environment = OutlivesEnvironment::new(param_env);
+ outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, span);
+ outlives_environment.save_implied_bounds(id);
+ let region_bound_pairs =
+ outlives_environment.region_bound_pairs_map().get(&id).unwrap();
+
+ let cause =
+ ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
+
+ let sup_type = *ty;
+ let sub_region = region;
+
+ let origin = SubregionOrigin::from_obligation_cause(&cause, || {
+ infer::RelateParamBound(cause.span, sup_type, None)
+ });
+
+ let outlives = &mut TypeOutlives::new(
+ &infcx,
+ tcx,
+ ®ion_bound_pairs,
+ Some(tcx.lifetimes.re_root_empty),
+ param_env,
);
- error.emit();
- }
+ outlives.type_must_outlive(origin, sup_type, sub_region);
+
+ let errors = infcx.resolve_regions(
+ trait_item.def_id.to_def_id(),
+ &outlives_environment,
+ RegionckMode::default(),
+ );
+
+ debug!(?errors, "errors");
+
+ if errors.is_empty() {
+ debug!(?ty_idx, ?region_idx);
+ debug!("required clause: {} must outlive {}", ty, region);
+ let ty_param = generics.param_at(*ty_idx, tcx);
+ let ty_param = tcx.mk_ty(ty::Param(ty::ParamTy {
+ index: ty_param.index,
+ name: ty_param.name,
+ }));
+ let region_param = generics.param_at(*region_idx, tcx);
+ // Then create a clause that is required on the GAT
+ let region_param =
+ tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
+ def_id: region_param.def_id,
+ index: region_param.index,
+ name: region_param.name,
+ }));
+ let clause = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
+ ty_param,
+ region_param,
+ ));
+ let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
+ clauses.insert(clause);
+ }
+ });
}
- })
+ }
+ }
+
+ // If there are any missing clauses, emit an error
+ debug!(?clauses);
+ if !clauses.is_empty() {
+ let written_predicates: ty::GenericPredicates<'_> = tcx.predicates_of(trait_item.def_id);
+ for clause in clauses {
+ let found = written_predicates.predicates.iter().find(|p| p.0 == clause).is_some();
+ debug!(?clause, ?found);
+ let mut error = tcx
+ .sess
+ .struct_span_err(trait_item.generics.span, &format!("Missing bound: {}", clause));
+ error.emit();
+ }
}
}
// Which region appears and which parameter index its subsituted for
regions: FxHashSet<(ty::Region<'tcx>, usize)>,
// Which params appears and which parameter index its subsituted for
- _types: FxHashSet<(Ty<'tcx>, usize)>,
+ types: FxHashSet<(Ty<'tcx>, usize)>,
}
impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() {
ty::Projection(p) if p.item_def_id == self.gat => {
- let (_, substs) = p.trait_ref_and_own_substs(self.tcx);
- self.regions.extend(substs.iter().enumerate().filter_map(|(idx, subst)| {
+ for (idx, subst) in p.substs.iter().enumerate() {
match subst.unpack() {
- GenericArgKind::Lifetime(lt) => Some((lt, idx)),
- _ => None,
+ GenericArgKind::Lifetime(lt) => {
+ self.regions.insert((lt, idx));
+ }
+ GenericArgKind::Type(t) => match t.kind() {
+ ty::Param(_) => {
+ self.types.insert((t, idx));
+ }
+ _ => {}
+ },
+ _ => {}
}
- }));
+ }
}
_ => {}
}